1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2019 Joël Krähemann
3  *
4  * This file is part of GSequencer.
5  *
6  * GSequencer is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU 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  * GSequencer 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 General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with GSequencer.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <ags/audio/ags_port.h>
21 
22 #include <ags/plugin/ags_plugin_port.h>
23 
24 #include <ags/audio/ags_automation.h>
25 
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include <ags/i18n.h>
30 
31 void ags_port_class_init(AgsPortClass *port_class);
32 void ags_port_connectable_interface_init(AgsConnectableInterface *connectable);
33 void ags_port_init(AgsPort *port);
34 void ags_port_set_property(GObject *gobject,
35 			   guint prop_id,
36 			   const GValue *value,
37 			   GParamSpec *param_spec);
38 void ags_port_get_property(GObject *gobject,
39 			   guint prop_id,
40 			   GValue *value,
41 			   GParamSpec *param_spec);
42 void ags_port_dispose(GObject *gobject);
43 void ags_port_finalize(GObject *gobject);
44 
45 AgsUUID* ags_port_get_uuid(AgsConnectable *connectable);
46 gboolean ags_port_has_resource(AgsConnectable *connectable);
47 gboolean ags_port_is_ready(AgsConnectable *connectable);
48 void ags_port_add_to_registry(AgsConnectable *connectable);
49 void ags_port_remove_from_registry(AgsConnectable *connectable);
50 xmlNode* ags_port_list_resource(AgsConnectable *connectable);
51 xmlNode* ags_port_xml_compose(AgsConnectable *connectable);
52 void ags_port_xml_parse(AgsConnectable *connectable,
53 			  xmlNode *node);
54 gboolean ags_port_is_connected(AgsConnectable *connectable);
55 void ags_port_connect(AgsConnectable *connectable);
56 void ags_port_disconnect(AgsConnectable *connectable);
57 
58 void ags_port_real_safe_read(AgsPort *port, GValue *value);
59 void ags_port_real_safe_write(AgsPort *port, GValue *value);
60 void ags_port_real_safe_get_property(AgsPort *port, gchar *property_name, GValue *value);
61 void ags_port_real_safe_set_property(AgsPort *port, gchar *property_name, GValue *value);
62 
63 /**
64  * SECTION:ags_port
65  * @short_description: Perform thread-safe operations
66  * @title: AgsPort
67  * @section_id:
68  * @include: ags/audio/ags_port.h
69  *
70  * #AgsPort provides a thread-safe way to access or change values or properties.
71  */
72 
73 enum{
74   SAFE_READ,
75   SAFE_WRITE,
76   SAFE_GET_PROPERTY,
77   SAFE_SET_PROPERTY,
78   LAST_SIGNAL,
79 };
80 
81 enum{
82   PROP_0,
83   PROP_PLUGIN_NAME,
84   PROP_SPECIFIER,
85   PROP_CONTROL_PORT,
86   PROP_PORT_VALUE_IS_POINTER,
87   PROP_PORT_VALUE_TYPE,
88   PROP_PORT_VALUE_SIZE,
89   PROP_PORT_VALUE_LENGTH,
90   PROP_PLUGIN_PORT,
91   PROP_CONVERSION,
92   PROP_AUTOMATION,
93   PROP_PORT_VALUE,
94 };
95 
96 static gpointer ags_port_parent_class = NULL;
97 static guint port_signals[LAST_SIGNAL];
98 
99 GType
ags_port_get_type(void)100 ags_port_get_type(void)
101 {
102   static volatile gsize g_define_type_id__volatile = 0;
103 
104   if(g_once_init_enter (&g_define_type_id__volatile)){
105     GType ags_type_port = 0;
106 
107     static const GTypeInfo ags_port_info = {
108       sizeof (AgsPortClass),
109       NULL, /* base_init */
110       NULL, /* base_finalize */
111       (GClassInitFunc) ags_port_class_init,
112       NULL, /* class_finalize */
113       NULL, /* class_data */
114       sizeof (AgsPort),
115       0,    /* n_preallocs */
116       (GInstanceInitFunc) ags_port_init,
117     };
118 
119     static const GInterfaceInfo ags_connectable_interface_info = {
120       (GInterfaceInitFunc) ags_port_connectable_interface_init,
121       NULL, /* interface_finalize */
122       NULL, /* interface_data */
123     };
124 
125     ags_type_port = g_type_register_static(G_TYPE_OBJECT,
126 					   "AgsPort",
127 					   &ags_port_info,
128 					   0);
129 
130     g_type_add_interface_static(ags_type_port,
131 				AGS_TYPE_CONNECTABLE,
132 				&ags_connectable_interface_info);
133 
134     g_once_init_leave(&g_define_type_id__volatile, ags_type_port);
135   }
136 
137   return g_define_type_id__volatile;
138 }
139 
140 void
ags_port_class_init(AgsPortClass * port)141 ags_port_class_init(AgsPortClass *port)
142 {
143   GObjectClass *gobject;
144   GParamSpec *param_spec;
145 
146   ags_port_parent_class = g_type_class_peek_parent(port);
147 
148   /* GObjectClass */
149   gobject = (GObjectClass *) port;
150 
151   gobject->set_property = ags_port_set_property;
152   gobject->get_property = ags_port_get_property;
153 
154   gobject->dispose = ags_port_dispose;
155   gobject->finalize = ags_port_finalize;
156 
157   /* properties */
158   /**
159    * AgsPort:plugin-name:
160    *
161    * The assigned plugin.
162    *
163    * Since: 3.0.0
164    */
165   param_spec = g_param_spec_string("plugin-name",
166 				   i18n_pspec("plugin-name of port"),
167 				   i18n_pspec("The plugin-name this port belongs to"),
168 				   NULL,
169 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
170   g_object_class_install_property(gobject,
171 				  PROP_PLUGIN_NAME,
172 				  param_spec);
173 
174   /**
175    * AgsPort:specifier:
176    *
177    * The assigned plugin identifier.
178    *
179    * Since: 3.0.0
180    */
181   param_spec = g_param_spec_string("specifier",
182 				   i18n_pspec("specifier of port"),
183 				   i18n_pspec("The specifier this port is identified by"),
184 				   NULL,
185 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
186   g_object_class_install_property(gobject,
187 				  PROP_SPECIFIER,
188 				  param_spec);
189 
190   /**
191    * AgsPort:control-port:
192    *
193    * The assigned plugin control port.
194    *
195    * Since: 3.0.0
196    */
197   param_spec = g_param_spec_string("control-port",
198 				   i18n_pspec("control-port of port"),
199 				   i18n_pspec("The control-port this port is numbered"),
200 				   NULL,
201 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
202   g_object_class_install_property(gobject,
203 				  PROP_CONTROL_PORT,
204 				  param_spec);
205 
206   /**
207    * AgsPort:port-value-is-pointer:
208    *
209    * Specify port data as pointer.
210    *
211    * Since: 3.0.0
212    */
213   param_spec = g_param_spec_boolean("port-value-is-pointer",
214 				    i18n_pspec("port-value-is-pointer indicates if value is a pointer"),
215 				    i18n_pspec("The port-value-is-pointer indicates if value is a pointer"),
216 				    FALSE,
217 				    G_PARAM_READABLE | G_PARAM_WRITABLE);
218   g_object_class_install_property(gobject,
219 				  PROP_PORT_VALUE_IS_POINTER,
220 				  param_spec);
221 
222   /**
223    * AgsPort:port-value-type:
224    *
225    * The port's data type.
226    *
227    * Since: 3.0.0
228    */
229   param_spec = g_param_spec_gtype("port-value-type",
230 				  i18n_pspec("port-value-type tells you the type of the values"),
231 				  i18n_pspec("The port-value-type tells you the type of the values"),
232 				  G_TYPE_NONE,
233 				  G_PARAM_READABLE | G_PARAM_WRITABLE);
234   g_object_class_install_property(gobject,
235 				  PROP_PORT_VALUE_TYPE,
236 				  param_spec);
237 
238   /**
239    * AgsPort:port-value-size:
240    *
241    * The port's data type size.
242    *
243    * Since: 3.0.0
244    */
245   param_spec = g_param_spec_uint("port-value-size",
246 				 i18n_pspec("port-value-size is the size of a single entry"),
247 				 i18n_pspec("The port-value-size is the size of a single entry"),
248 				 1,
249 				 16,
250 				 sizeof(gdouble),
251 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
252   g_object_class_install_property(gobject,
253 				  PROP_PORT_VALUE_SIZE,
254 				  param_spec);
255 
256   /**
257    * AgsPort:port-value-length:
258    *
259    * The port's data array length.
260    *
261    * Since: 3.0.0
262    */
263   param_spec = g_param_spec_uint("port-value-length",
264 				 i18n_pspec("port-value-length is the array size"),
265 				 i18n_pspec("The port-value-length is the array size"),
266 				 0,
267 				 G_MAXUINT32,
268 				 1,
269 				 G_PARAM_READABLE | G_PARAM_WRITABLE);
270   g_object_class_install_property(gobject,
271 				  PROP_PORT_VALUE_LENGTH,
272 				  param_spec);
273 
274   /**
275    * AgsPort:plugin-port:
276    *
277    * The plugin-port.
278    *
279    * Since: 3.0.0
280    */
281   param_spec = g_param_spec_object("plugin-port",
282 				   i18n_pspec("plugin port"),
283 				   i18n_pspec("The plugin port"),
284 				   AGS_TYPE_PLUGIN_PORT,
285 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
286   g_object_class_install_property(gobject,
287 				  PROP_PLUGIN_PORT,
288 				  param_spec);
289 
290   /**
291    * AgsPort:conversion:
292    *
293    * The port's conversion object.
294    *
295    * Since: 3.0.0
296    */
297   param_spec = g_param_spec_object("conversion",
298 				   i18n_pspec("conversion converts values"),
299 				   i18n_pspec("The conversion is able to translate values"),
300 				   AGS_TYPE_CONVERSION,
301 				   G_PARAM_READABLE | G_PARAM_WRITABLE);
302   g_object_class_install_property(gobject,
303 				  PROP_CONVERSION,
304 				  param_spec);
305 
306   /**
307    * AgsPort:automation: (type GList(AgsAutomation)) (transfer full)
308    *
309    * The port's automation.
310    *
311    * Since: 3.0.0
312    */
313   param_spec = g_param_spec_pointer("automation",
314 				    i18n_pspec("automation"),
315 				    i18n_pspec("The automation to apply"),
316 				    G_PARAM_READABLE | G_PARAM_WRITABLE);
317   g_object_class_install_property(gobject,
318 				  PROP_AUTOMATION,
319 				  param_spec);
320 
321   /* AgsPortClass */
322   port->safe_read = ags_port_real_safe_read;
323   port->safe_write = ags_port_real_safe_write;
324 
325   port->safe_get_property = ags_port_real_safe_get_property;
326   port->safe_set_property = ags_port_real_safe_set_property;
327 
328   /* signals */
329   /**
330    * AgsPort::safe-read:
331    * @port: the object providing safe read
332    * @value: the #GValue-struct
333    *
334    * The ::safe-read signal is emited while doing safe read operation.
335    *
336    * Since: 3.0.0
337    */
338   port_signals[SAFE_READ] =
339     g_signal_new("safe-read",
340 		 G_TYPE_FROM_CLASS (port),
341 		 G_SIGNAL_RUN_LAST,
342 		 G_STRUCT_OFFSET (AgsPortClass, safe_read),
343 		 NULL, NULL,
344 		 g_cclosure_marshal_VOID__POINTER,
345 		 G_TYPE_NONE, 1,
346 		 G_TYPE_POINTER);
347 
348   /**
349    * AgsPort::safe-write:
350    * @port: the object providing safe write
351    * @value: the #GValue-struct
352    *
353    * The ::safe-write signal is emited while doing safe write operation.
354    *
355    * Since: 3.0.0
356    */
357   port_signals[SAFE_WRITE] =
358     g_signal_new("safe-write",
359 		 G_TYPE_FROM_CLASS (port),
360 		 G_SIGNAL_RUN_LAST,
361 		 G_STRUCT_OFFSET (AgsPortClass, safe_write),
362 		 NULL, NULL,
363 		 g_cclosure_marshal_VOID__POINTER,
364 		 G_TYPE_NONE, 1,
365 		 G_TYPE_POINTER);
366 
367   /**
368    * AgsPort::safe-get-property:
369    * @port: the object providing safe get property
370    * @property_name: the property name
371    * @value: the #GValue-struct
372    *
373    * The ::safe-get-property signal is emited while safe get property.
374    *
375    * Since: 3.0.0
376    */
377   port_signals[SAFE_GET_PROPERTY] =
378     g_signal_new("safe-get-property",
379 		 G_TYPE_FROM_CLASS (port),
380 		 G_SIGNAL_RUN_LAST,
381 		 G_STRUCT_OFFSET (AgsPortClass, safe_get_property),
382 		 NULL, NULL,
383 		 ags_cclosure_marshal_VOID__STRING_POINTER,
384 		 G_TYPE_NONE, 2,
385 		 G_TYPE_STRING, G_TYPE_POINTER);
386 
387   /**
388    * AgsPort::safe-set-property:
389    * @port: the object providing safe set property
390    * @property_name: the property name
391    * @value: the #GValue-struct
392    *
393    * The ::safe-set-property signal is emited while safe set property.
394    *
395    * Since: 3.0.0
396    */
397   port_signals[SAFE_SET_PROPERTY] =
398     g_signal_new("safe-set-property",
399 		 G_TYPE_FROM_CLASS (port),
400 		 G_SIGNAL_RUN_LAST,
401 		 G_STRUCT_OFFSET (AgsPortClass, safe_set_property),
402 		 NULL, NULL,
403 		 ags_cclosure_marshal_VOID__STRING_POINTER,
404 		 G_TYPE_NONE, 2,
405 		 G_TYPE_STRING, G_TYPE_POINTER);
406 }
407 
408 void
ags_port_connectable_interface_init(AgsConnectableInterface * connectable)409 ags_port_connectable_interface_init(AgsConnectableInterface *connectable)
410 {
411   connectable->get_uuid = ags_port_get_uuid;
412   connectable->has_resource = ags_port_has_resource;
413 
414   connectable->is_ready = ags_port_is_ready;
415   connectable->add_to_registry = ags_port_add_to_registry;
416   connectable->remove_from_registry = ags_port_remove_from_registry;
417 
418   connectable->list_resource = ags_port_list_resource;
419   connectable->xml_compose = ags_port_xml_compose;
420   connectable->xml_parse = ags_port_xml_parse;
421 
422   connectable->is_connected = ags_port_is_connected;
423   connectable->connect = ags_port_connect;
424   connectable->disconnect = ags_port_disconnect;
425 
426   connectable->connect_connection = NULL;
427   connectable->disconnect_connection = NULL;
428 }
429 
430 void
ags_port_init(AgsPort * port)431 ags_port_init(AgsPort *port)
432 {
433   port->flags = 0; // AGS_PORT_CONVERT_ALWAYS;
434 
435   /* port mutex */
436   g_rec_mutex_init(&(port->obj_mutex));
437 
438   /* common fields */
439   port->plugin_name = NULL;
440   port->specifier = NULL;
441 
442   port->control_port = NULL;
443 
444   port->port_value_is_pointer = FALSE;
445   port->port_value_type = G_TYPE_DOUBLE;
446 
447   port->port_value_size = sizeof(gdouble);
448   port->port_value_length = 1;
449 
450   port->plugin_port = NULL;
451 
452   port->conversion = ags_conversion_new();
453   g_object_ref(port->conversion);
454 
455   port->automation = NULL;
456 
457   port->port_value.ags_port_double = 0.0;
458 }
459 
460 void
ags_port_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)461 ags_port_set_property(GObject *gobject,
462 		      guint prop_id,
463 		      const GValue *value,
464 		      GParamSpec *param_spec)
465 {
466   AgsPort *port;
467 
468   GRecMutex *port_mutex;
469 
470   port = AGS_PORT(gobject);
471 
472   /* get port mutex */
473   port_mutex = AGS_PORT_GET_OBJ_MUTEX(port);
474 
475   switch(prop_id){
476   case PROP_PLUGIN_NAME:
477     {
478       gchar *plugin_name;
479 
480       plugin_name = (gchar *) g_value_get_string(value);
481 
482       g_rec_mutex_lock(port_mutex);
483 
484       if(port->plugin_name == plugin_name){
485 	g_rec_mutex_unlock(port_mutex);
486 
487 	return;
488       }
489 
490       if(port->plugin_name != NULL){
491 	g_free(port->plugin_name);
492       }
493 
494       port->plugin_name = g_strdup(plugin_name);
495 
496       g_rec_mutex_unlock(port_mutex);
497     }
498     break;
499   case PROP_SPECIFIER:
500     {
501       gchar *specifier;
502 
503       specifier = (gchar *) g_value_get_string(value);
504 
505       g_rec_mutex_lock(port_mutex);
506 
507       if(port->specifier == specifier){
508 	g_rec_mutex_unlock(port_mutex);
509 
510 	return;
511       }
512 
513       if(port->specifier != NULL){
514 	g_free(port->specifier);
515       }
516 
517       port->specifier = g_strdup(specifier);
518 
519       g_rec_mutex_unlock(port_mutex);
520     }
521     break;
522   case PROP_CONTROL_PORT:
523     {
524       gchar *control_port;
525 
526       control_port = (gchar *) g_value_get_string(value);
527 
528       g_rec_mutex_lock(port_mutex);
529 
530       if(port->control_port == control_port){
531 	g_rec_mutex_unlock(port_mutex);
532 
533 	return;
534       }
535 
536       if(port->control_port != NULL){
537 	g_free(port->control_port);
538       }
539 
540       port->control_port = g_strdup(control_port);
541 
542       g_rec_mutex_unlock(port_mutex);
543     }
544     break;
545   case PROP_PORT_VALUE_IS_POINTER:
546     {
547       g_rec_mutex_lock(port_mutex);
548 
549       port->port_value_is_pointer = g_value_get_boolean(value);
550 
551       g_rec_mutex_unlock(port_mutex);
552     }
553     break;
554   case PROP_PORT_VALUE_TYPE:
555     {
556       g_rec_mutex_lock(port_mutex);
557 
558       port->port_value_type = g_value_get_gtype(value);
559 
560       g_rec_mutex_unlock(port_mutex);
561     }
562     break;
563   case PROP_PORT_VALUE_SIZE:
564     {
565       g_rec_mutex_lock(port_mutex);
566 
567       port->port_value_size = g_value_get_uint(value);
568 
569       g_rec_mutex_unlock(port_mutex);
570     }
571     break;
572   case PROP_PORT_VALUE_LENGTH:
573     {
574       g_rec_mutex_lock(port_mutex);
575 
576       port->port_value_length = g_value_get_uint(value);
577 
578       g_rec_mutex_unlock(port_mutex);
579     }
580     break;
581   case PROP_PLUGIN_PORT:
582     {
583       AgsPluginPort *plugin_port;
584 
585       plugin_port = g_value_get_object(value);
586 
587       g_rec_mutex_lock(port_mutex);
588 
589       if(plugin_port == (AgsPluginPort *) port->plugin_port){
590 	g_rec_mutex_unlock(port_mutex);
591 
592 	return;
593       }
594 
595       if(port->plugin_port != NULL){
596 	g_object_unref(port->plugin_port);
597       }
598 
599       if(plugin_port != NULL){
600 	g_object_ref(plugin_port);
601       }
602 
603       port->plugin_port = (GObject *) plugin_port;
604 
605       g_rec_mutex_unlock(port_mutex);
606     }
607     break;
608   case PROP_CONVERSION:
609     {
610       AgsConversion *conversion;
611 
612       conversion = g_value_get_object(value);
613 
614       g_rec_mutex_lock(port_mutex);
615 
616       if(conversion == port->conversion){
617 	g_rec_mutex_unlock(port_mutex);
618 
619 	return;
620       }
621 
622       if(port->conversion != NULL){
623 	g_object_unref(port->conversion);
624       }
625 
626       if(conversion != NULL){
627 	g_object_ref(conversion);
628       }
629 
630       port->conversion = conversion;
631 
632       g_rec_mutex_unlock(port_mutex);
633     }
634     break;
635   case PROP_AUTOMATION:
636     {
637       AgsAutomation *automation;
638 
639       automation = g_value_get_pointer(value);
640 
641       if(g_list_find(port->automation, automation) != NULL){
642 	g_rec_mutex_unlock(port_mutex);
643 
644 	return;
645       }
646 
647       if(automation != NULL){
648 	g_object_ref(automation);
649       }
650 
651       port->automation = ags_automation_add(port->automation,
652 					    automation);
653 
654       g_rec_mutex_unlock(port_mutex);
655     }
656     break;
657   default:
658     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
659     break;
660   }
661 }
662 
663 void
ags_port_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)664 ags_port_get_property(GObject *gobject,
665 		      guint prop_id,
666 		      GValue *value,
667 		      GParamSpec *param_spec)
668 {
669   AgsPort *port;
670 
671   GRecMutex *port_mutex;
672 
673   port = AGS_PORT(gobject);
674 
675   /* get port mutex */
676   port_mutex = AGS_PORT_GET_OBJ_MUTEX(port);
677 
678   switch(prop_id){
679   case PROP_PLUGIN_NAME:
680     {
681       g_rec_mutex_lock(port_mutex);
682 
683       g_value_set_string(value, port->plugin_name);
684 
685       g_rec_mutex_unlock(port_mutex);
686     }
687     break;
688   case PROP_SPECIFIER:
689     {
690       g_rec_mutex_lock(port_mutex);
691 
692       g_value_set_string(value, port->specifier);
693 
694       g_rec_mutex_unlock(port_mutex);
695     }
696     break;
697   case PROP_CONTROL_PORT:
698     {
699       g_rec_mutex_lock(port_mutex);
700 
701       g_value_set_string(value, port->control_port);
702 
703       g_rec_mutex_unlock(port_mutex);
704     }
705     break;
706   case PROP_PORT_VALUE_IS_POINTER:
707     {
708       g_rec_mutex_lock(port_mutex);
709 
710       g_value_set_boolean(value, port->port_value_is_pointer);
711 
712       g_rec_mutex_unlock(port_mutex);
713     }
714     break;
715   case PROP_PORT_VALUE_TYPE:
716     {
717       g_rec_mutex_lock(port_mutex);
718 
719       g_value_set_gtype(value, port->port_value_type);
720 
721       g_rec_mutex_unlock(port_mutex);
722     }
723     break;
724   case PROP_PORT_VALUE_SIZE:
725     {
726       g_rec_mutex_lock(port_mutex);
727 
728       g_value_set_uint(value, port->port_value_size);
729 
730       g_rec_mutex_unlock(port_mutex);
731     }
732     break;
733   case PROP_PORT_VALUE_LENGTH:
734     {
735       g_rec_mutex_lock(port_mutex);
736 
737       g_value_set_uint(value, port->port_value_length);
738 
739       g_rec_mutex_unlock(port_mutex);
740     }
741     break;
742   case PROP_PLUGIN_PORT:
743     {
744       g_rec_mutex_lock(port_mutex);
745 
746       g_value_set_object(value, port->plugin_port);
747 
748       g_rec_mutex_unlock(port_mutex);
749     }
750     break;
751   case PROP_CONVERSION:
752     {
753       g_rec_mutex_lock(port_mutex);
754 
755       g_value_set_object(value, port->conversion);
756 
757       g_rec_mutex_unlock(port_mutex);
758     }
759     break;
760   case PROP_AUTOMATION:
761     {
762       g_rec_mutex_lock(port_mutex);
763 
764       g_value_set_pointer(value, g_list_copy_deep(port->automation,
765 						  (GCopyFunc) g_object_ref,
766 						  NULL));
767 
768       g_rec_mutex_unlock(port_mutex);
769     }
770     break;
771   default:
772     G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
773     break;
774   }
775 }
776 
777 void
ags_port_dispose(GObject * gobject)778 ags_port_dispose(GObject *gobject)
779 {
780   AgsPort *port;
781 
782   port = AGS_PORT(gobject);
783 
784   if(port->plugin_port != NULL){
785     g_object_unref(port->plugin_port);
786 
787     port->plugin_port = NULL;
788   }
789 
790   if(port->conversion != NULL){
791     g_object_unref(port->conversion);
792 
793     port->conversion = NULL;
794   }
795 
796   if(port->automation != NULL){
797     g_list_free_full(port->automation,
798 		     g_object_unref);
799 
800     port->automation = NULL;
801   }
802 
803   /* call parent */
804   G_OBJECT_CLASS(ags_port_parent_class)->dispose(gobject);
805 }
806 
807 void
ags_port_finalize(GObject * gobject)808 ags_port_finalize(GObject *gobject)
809 {
810   AgsPort *port;
811 
812   port = AGS_PORT(gobject);
813 
814   g_free(port->plugin_name);
815   g_free(port->specifier);
816 
817   g_free(port->control_port);
818 
819   if(port->plugin_port != NULL){
820     g_object_unref(port->plugin_port);
821   }
822 
823   if(port->conversion != NULL){
824     g_object_unref(port->conversion);
825   }
826 
827   if(port->automation != NULL){
828     g_list_free_full(port->automation,
829 		     g_object_unref);
830   }
831 
832   /* call parent */
833   G_OBJECT_CLASS(ags_port_parent_class)->finalize(gobject);
834 }
835 
836 AgsUUID*
ags_port_get_uuid(AgsConnectable * connectable)837 ags_port_get_uuid(AgsConnectable *connectable)
838 {
839   AgsPort *port;
840 
841   AgsUUID *ptr;
842 
843   GRecMutex *port_mutex;
844 
845   port = AGS_PORT(connectable);
846 
847   /* get port mutex */
848   port_mutex = AGS_PORT_GET_OBJ_MUTEX(port);
849 
850   /* get UUID */
851   g_rec_mutex_lock(port_mutex);
852 
853   ptr = port->uuid;
854 
855   g_rec_mutex_unlock(port_mutex);
856 
857   return(ptr);
858 }
859 
860 gboolean
ags_port_has_resource(AgsConnectable * connectable)861 ags_port_has_resource(AgsConnectable *connectable)
862 {
863   return(TRUE);
864 }
865 
866 gboolean
ags_port_is_ready(AgsConnectable * connectable)867 ags_port_is_ready(AgsConnectable *connectable)
868 {
869   AgsPort *port;
870 
871   gboolean is_ready;
872 
873   port = AGS_PORT(connectable);
874 
875   /* check is added */
876   is_ready = ags_port_test_flags(port, AGS_PORT_ADDED_TO_REGISTRY);
877 
878   return(is_ready);
879 }
880 
881 void
ags_port_add_to_registry(AgsConnectable * connectable)882 ags_port_add_to_registry(AgsConnectable *connectable)
883 {
884   AgsPort *port;
885 
886   AgsRegistry *registry;
887   AgsRegistryEntry *entry;
888 
889   AgsApplicationContext *application_context;
890 
891   GList *list;
892 
893   if(ags_connectable_is_ready(connectable)){
894     return;
895   }
896 
897   port = AGS_PORT(connectable);
898 
899   ags_port_set_flags(port, AGS_PORT_ADDED_TO_REGISTRY);
900 
901   application_context = ags_application_context_get_instance();
902 
903   registry = ags_service_provider_get_registry(AGS_SERVICE_PROVIDER(application_context));
904 
905   if(registry != NULL){
906     entry = ags_registry_entry_alloc(registry);
907     g_value_set_object(entry->entry,
908 		       (gpointer) port);
909     ags_registry_add_entry(registry,
910 			   entry);
911   }
912 
913   //TODO:JK: implement me
914 }
915 
916 void
ags_port_remove_from_registry(AgsConnectable * connectable)917 ags_port_remove_from_registry(AgsConnectable *connectable)
918 {
919   if(!ags_connectable_is_ready(connectable)){
920     return;
921   }
922 
923   //TODO:JK: implement me
924 }
925 
926 xmlNode*
ags_port_list_resource(AgsConnectable * connectable)927 ags_port_list_resource(AgsConnectable *connectable)
928 {
929   xmlNode *node;
930 
931   node = NULL;
932 
933   //TODO:JK: implement me
934 
935   return(node);
936 }
937 
938 xmlNode*
ags_port_xml_compose(AgsConnectable * connectable)939 ags_port_xml_compose(AgsConnectable *connectable)
940 {
941   xmlNode *node;
942 
943   node = NULL;
944 
945   //TODO:JK: implement me
946 
947   return(node);
948 }
949 
950 void
ags_port_xml_parse(AgsConnectable * connectable,xmlNode * node)951 ags_port_xml_parse(AgsConnectable *connectable,
952 		     xmlNode *node)
953 {
954   //TODO:JK: implement me
955 }
956 
957 gboolean
ags_port_is_connected(AgsConnectable * connectable)958 ags_port_is_connected(AgsConnectable *connectable)
959 {
960   AgsPort *port;
961 
962   gboolean is_connected;
963 
964   port = AGS_PORT(connectable);
965 
966   /* check is connected */
967   is_connected = ags_port_test_flags(port, AGS_PORT_CONNECTED);
968 
969   return(is_connected);
970 }
971 
972 void
ags_port_connect(AgsConnectable * connectable)973 ags_port_connect(AgsConnectable *connectable)
974 {
975   AgsPort *port;
976 
977   GList *list_start, *list;
978 
979   GRecMutex *port_mutex;
980 
981   if(ags_connectable_is_connected(connectable)){
982     return;
983   }
984 
985   port = AGS_PORT(connectable);
986 
987   ags_port_set_flags(port, AGS_PORT_CONNECTED);
988 }
989 
990 void
ags_port_disconnect(AgsConnectable * connectable)991 ags_port_disconnect(AgsConnectable *connectable)
992 {
993   AgsPort *port;
994 
995   GList *list_start, *list;
996 
997   GRecMutex *port_mutex;
998 
999   if(!ags_connectable_is_connected(connectable)){
1000     return;
1001   }
1002 
1003   port = AGS_PORT(connectable);
1004 
1005   ags_port_unset_flags(port, AGS_PORT_CONNECTED);
1006 }
1007 
1008 /**
1009  * ags_port_test_flags:
1010  * @port: the #AgsPort
1011  * @flags: the flags
1012  *
1013  * Test @flags to be set on @port.
1014  *
1015  * Returns: %TRUE if flags are set, else %FALSE
1016  *
1017  * Since: 3.0.0
1018  */
1019 gboolean
ags_port_test_flags(AgsPort * port,guint flags)1020 ags_port_test_flags(AgsPort *port, guint flags)
1021 {
1022   gboolean retval;
1023 
1024   GRecMutex *port_mutex;
1025 
1026   if(!AGS_IS_PORT(port)){
1027     return(FALSE);
1028   }
1029 
1030   /* get port mutex */
1031   port_mutex = AGS_PORT_GET_OBJ_MUTEX(port);
1032 
1033   /* test */
1034   g_rec_mutex_lock(port_mutex);
1035 
1036   retval = (flags & (port->flags)) ? TRUE: FALSE;
1037 
1038   g_rec_mutex_unlock(port_mutex);
1039 
1040   return(retval);
1041 }
1042 
1043 /**
1044  * ags_port_set_flags:
1045  * @port: the #AgsPort
1046  * @flags: the flags
1047  *
1048  * Set flags.
1049  *
1050  * Since: 3.0.0
1051  */
1052 void
ags_port_set_flags(AgsPort * port,guint flags)1053 ags_port_set_flags(AgsPort *port, guint flags)
1054 {
1055   GRecMutex *port_mutex;
1056 
1057   if(!AGS_IS_PORT(port)){
1058     return;
1059   }
1060 
1061   /* get port mutex */
1062   port_mutex = AGS_PORT_GET_OBJ_MUTEX(port);
1063 
1064   /* set flags */
1065   g_rec_mutex_lock(port_mutex);
1066 
1067   port->flags |= flags;
1068 
1069   g_rec_mutex_unlock(port_mutex);
1070 }
1071 
1072 /**
1073  * ags_port_unset_flags:
1074  * @port: the #AgsPort
1075  * @flags: the flags
1076  *
1077  * Unset flags.
1078  *
1079  * Since: 3.0.0
1080  */
1081 void
ags_port_unset_flags(AgsPort * port,guint flags)1082 ags_port_unset_flags(AgsPort *port, guint flags)
1083 {
1084   GRecMutex *port_mutex;
1085 
1086   if(!AGS_IS_PORT(port)){
1087     return;
1088   }
1089 
1090   /* get port mutex */
1091   port_mutex = AGS_PORT_GET_OBJ_MUTEX(port);
1092 
1093   /* set flags */
1094   g_rec_mutex_lock(port_mutex);
1095 
1096   port->flags &= (~flags);
1097 
1098   g_rec_mutex_unlock(port_mutex);
1099 }
1100 
1101 void
ags_port_real_safe_read(AgsPort * port,GValue * value)1102 ags_port_real_safe_read(AgsPort *port, GValue *value)
1103 {
1104   guint overall_size;
1105   gpointer data;
1106 
1107   GRecMutex *port_mutex;
1108 
1109   /* get port mutex */
1110   port_mutex = AGS_PORT_GET_OBJ_MUTEX(port);
1111 
1112   /* safe read */
1113   g_rec_mutex_lock(port_mutex);
1114 
1115   overall_size = port->port_value_length * port->port_value_size;
1116 
1117   if(!port->port_value_is_pointer){
1118     if(port->port_value_type == G_TYPE_BOOLEAN){
1119       g_value_set_boolean(value, port->port_value.ags_port_boolean);
1120     }else if(port->port_value_type == G_TYPE_INT64){
1121       g_value_set_int64(value, port->port_value.ags_port_int);
1122     }else if(port->port_value_type == G_TYPE_UINT64){
1123       g_value_set_uint64(value, port->port_value.ags_port_uint);
1124     }else if(port->port_value_type == G_TYPE_FLOAT){
1125       gfloat new_value;
1126 
1127       if((AGS_PORT_CONVERT_ALWAYS & (port->flags)) != 0){
1128         new_value = (gfloat) ags_conversion_convert(port->conversion,
1129 						    (double) port->port_value.ags_port_float,
1130 						    TRUE);
1131       }else{
1132 	new_value = port->port_value.ags_port_float;
1133       }
1134 
1135       g_value_set_float(value, new_value);
1136     }else if(port->port_value_type == G_TYPE_DOUBLE){
1137       gdouble new_value;
1138 
1139       if((AGS_PORT_CONVERT_ALWAYS & (port->flags)) != 0){
1140         new_value = ags_conversion_convert(port->conversion,
1141 					   port->port_value.ags_port_double,
1142 					   TRUE);
1143       }else{
1144 	new_value = port->port_value.ags_port_double;
1145       }
1146 
1147       g_value_set_double(value, new_value);
1148     }else{
1149       data = NULL;
1150 
1151       if(port->port_value_type == G_TYPE_POINTER){
1152 	data = port->port_value.ags_port_pointer;
1153       }else if(port->port_value_type == G_TYPE_OBJECT){
1154 	data = port->port_value.ags_port_object;
1155       }
1156 
1157       g_value_set_pointer(value, data);
1158     }
1159   }else{
1160     data = NULL;
1161 
1162     if(port->port_value_type == G_TYPE_STRING){
1163       data = g_strdup(port->port_value.ags_port_string);
1164     }else if(port->port_value_type == G_TYPE_POINTER){
1165       data = port->port_value.ags_port_pointer;
1166     }else if(port->port_value_type == G_TYPE_OBJECT){
1167       data = port->port_value.ags_port_object;
1168     }else{
1169       data = (gpointer) g_value_get_pointer(value);
1170 
1171       if(port->port_value_type == G_TYPE_BOOLEAN){
1172 	memcpy(data, port->port_value.ags_port_boolean_ptr, overall_size);
1173       }else if(port->port_value_type == G_TYPE_INT64){
1174 	memcpy(data, port->port_value.ags_port_int_ptr, overall_size);
1175       }else if(port->port_value_type == G_TYPE_UINT64){
1176 	memcpy(data, port->port_value.ags_port_uint_ptr, overall_size);
1177       }else if(port->port_value_type == G_TYPE_FLOAT){
1178 	guint i;
1179 
1180 	for(i = 0; i < port->port_value_length; i++){
1181 	  //	  g_message("port[0x%x]: %f", port, port->port_value.ags_port_float_ptr[i]);
1182 	  ((gfloat *) data)[i] = port->port_value.ags_port_float_ptr[i];
1183 	}
1184       }else if(port->port_value_type == G_TYPE_DOUBLE){
1185 	guint i;
1186 
1187 	for(i = 0; i < port->port_value_length; i++){
1188 	  //	  g_message("port[0x%x]: %f", port, port->port_value.ags_port_double_ptr[i]);
1189 	  ((gdouble *) data)[i] = port->port_value.ags_port_double_ptr[i];
1190 	}
1191       }
1192     }
1193 
1194     g_value_set_pointer(value, data);
1195   }
1196 
1197   g_rec_mutex_unlock(port_mutex);
1198 }
1199 
1200 /**
1201  * ags_port_safe_read:
1202  * @port: an #AgsPort
1203  * @value: the #GValue to store result
1204  *
1205  * Perform safe read.
1206  *
1207  * Since: 3.0.0
1208  */
1209 void
ags_port_safe_read(AgsPort * port,GValue * value)1210 ags_port_safe_read(AgsPort *port, GValue *value)
1211 {
1212   g_return_if_fail(AGS_IS_PORT(port));
1213   g_object_ref(G_OBJECT(port));
1214   g_signal_emit(G_OBJECT(port),
1215 		port_signals[SAFE_READ], 0,
1216 		value);
1217   g_object_unref(G_OBJECT(port));
1218 }
1219 
1220 /**
1221  * ags_port_safe_read_raw:
1222  * @port: an #AgsPort
1223  * @value: the #GValue to store result
1224  *
1225  * Perform safe read.
1226  *
1227  * Since: 3.0.0
1228  */
1229 void
ags_port_safe_read_raw(AgsPort * port,GValue * value)1230 ags_port_safe_read_raw(AgsPort *port, GValue *value)
1231 {
1232   guint overall_size;
1233   gpointer data;
1234 
1235   GRecMutex *port_mutex;
1236 
1237   /* get port mutex */
1238   port_mutex = AGS_PORT_GET_OBJ_MUTEX(port);
1239 
1240   /* safe read */
1241   g_rec_mutex_lock(port_mutex);
1242 
1243   overall_size = port->port_value_length * port->port_value_size;
1244 
1245   if(!port->port_value_is_pointer){
1246     if(port->port_value_type == G_TYPE_BOOLEAN){
1247       g_value_set_boolean(value, port->port_value.ags_port_boolean);
1248     }else if(port->port_value_type == G_TYPE_INT64){
1249       g_value_set_int64(value, port->port_value.ags_port_int);
1250     }else if(port->port_value_type == G_TYPE_UINT64){
1251       g_value_set_uint64(value, port->port_value.ags_port_uint);
1252     }else if(port->port_value_type == G_TYPE_FLOAT){
1253       gfloat new_value;
1254 
1255       new_value = port->port_value.ags_port_float;
1256 
1257       g_value_set_float(value, new_value);
1258     }else if(port->port_value_type == G_TYPE_DOUBLE){
1259       gdouble new_value;
1260 
1261       new_value = port->port_value.ags_port_double;
1262 
1263       g_value_set_double(value, new_value);
1264     }else{
1265       data = NULL;
1266 
1267       if(port->port_value_type == G_TYPE_POINTER){
1268 	data = port->port_value.ags_port_pointer;
1269       }else if(port->port_value_type == G_TYPE_OBJECT){
1270 	data = port->port_value.ags_port_object;
1271       }
1272 
1273       g_value_set_pointer(value, data);
1274     }
1275   }else{
1276     data = NULL;
1277 
1278     if(port->port_value_type == G_TYPE_POINTER){
1279       data = port->port_value.ags_port_pointer;
1280     }else if(port->port_value_type == G_TYPE_OBJECT){
1281       data = port->port_value.ags_port_object;
1282     }else{
1283       data = (gpointer) g_malloc(overall_size);
1284 
1285       if(port->port_value_type == G_TYPE_BOOLEAN){
1286 	memcpy(data, port->port_value.ags_port_boolean_ptr, overall_size);
1287       }else if(port->port_value_type == G_TYPE_INT64){
1288 	memcpy(data, port->port_value.ags_port_int_ptr, overall_size);
1289       }else if(port->port_value_type == G_TYPE_UINT64){
1290 	memcpy(data, port->port_value.ags_port_uint_ptr, overall_size);
1291       }else if(port->port_value_type == G_TYPE_FLOAT){
1292 	guint i;
1293 
1294 	for(i = 0; i < port->port_value_length; i++){
1295 	  ((gfloat *) data)[i] = port->port_value.ags_port_float_ptr[i];
1296 	}
1297       }else if(port->port_value_type == G_TYPE_DOUBLE){
1298 	guint i;
1299 
1300 	for(i = 0; i < port->port_value_length; i++){
1301 	  ((gdouble *) data)[i] = port->port_value.ags_port_double_ptr[i];
1302 	}
1303       }
1304     }
1305 
1306     g_value_set_pointer(value, data);
1307   }
1308 
1309   g_rec_mutex_unlock(port_mutex);
1310 }
1311 
1312 void
ags_port_real_safe_write(AgsPort * port,GValue * value)1313 ags_port_real_safe_write(AgsPort *port, GValue *value)
1314 {
1315   guint overall_size;
1316   gpointer data;
1317 
1318   GRecMutex *port_mutex;
1319 
1320   /* get port mutex */
1321   port_mutex = AGS_PORT_GET_OBJ_MUTEX(port);
1322 
1323   /* write */
1324   g_rec_mutex_lock(port_mutex);
1325 
1326   overall_size = port->port_value_length * port->port_value_size;
1327 
1328   if(!port->port_value_is_pointer){
1329     if(port->port_value_type == G_TYPE_BOOLEAN){
1330       port->port_value.ags_port_boolean = g_value_get_boolean(value);
1331     }else if(port->port_value_type == G_TYPE_INT64){
1332       port->port_value.ags_port_int = g_value_get_int64(value);
1333     }else if(port->port_value_type == G_TYPE_UINT64){
1334       port->port_value.ags_port_uint = g_value_get_uint64(value);
1335     }else if(port->port_value_type == G_TYPE_FLOAT){
1336       if((AGS_PORT_CONVERT_ALWAYS & (port->flags)) != 0 &&
1337 	 port->conversion != NULL){
1338 	if((AGS_PORT_USE_LADSPA_FLOAT & (port->flags)) == 0){
1339 	  port->port_value.ags_port_float = (gfloat) ags_conversion_convert(port->conversion,
1340 									    (double) g_value_get_float(value),
1341 									    FALSE);
1342 	}else{
1343 	  LADSPA_Data val;
1344 
1345 	  val = g_value_get_float(value);
1346 	  port->port_value.ags_port_ladspa = (LADSPA_Data) ags_conversion_convert(port->conversion,
1347 										  (double) val,
1348 										  FALSE);
1349 	}
1350       }else{
1351 	if((AGS_PORT_USE_LADSPA_FLOAT & (port->flags)) == 0){
1352 	  port->port_value.ags_port_float = (gfloat) g_value_get_float(value);
1353 	}else{
1354 	  port->port_value.ags_port_ladspa = (LADSPA_Data) g_value_get_float(value);
1355 	}
1356       }
1357     }else if(port->port_value_type == G_TYPE_DOUBLE){
1358       if((AGS_PORT_CONVERT_ALWAYS & (port->flags)) != 0 &&
1359 	 port->conversion != NULL){
1360 	port->port_value.ags_port_double = ags_conversion_convert(port->conversion,
1361 								  g_value_get_double(value),
1362 								  FALSE);
1363       }else{
1364 	port->port_value.ags_port_double = g_value_get_double(value);
1365       }
1366     }else if(port->port_value_type == G_TYPE_POINTER){
1367       port->port_value.ags_port_pointer = g_value_get_pointer(value);
1368     }else if(port->port_value_type == G_TYPE_OBJECT){
1369       port->port_value.ags_port_object = g_value_get_object(value);
1370     }else{
1371       g_warning("ags_port.c: unknown type");
1372     }
1373   }else{
1374     data = g_value_get_pointer(value);
1375 
1376     if(port->port_value_type == G_TYPE_BOOLEAN){
1377       memcpy(port->port_value.ags_port_boolean_ptr, data, overall_size);
1378     }else if(port->port_value_type == G_TYPE_INT64){
1379       memcpy(port->port_value.ags_port_int_ptr, data, overall_size);
1380     }else if(port->port_value_type == G_TYPE_UINT64){
1381       memcpy(port->port_value.ags_port_uint_ptr, data, overall_size);
1382     }else if(port->port_value_type == G_TYPE_DOUBLE){
1383       memcpy(port->port_value.ags_port_double_ptr, data, overall_size);
1384     }else if(port->port_value_type == G_TYPE_POINTER){
1385       port->port_value.ags_port_pointer = data;
1386     }else{
1387       data = g_value_get_object(value);
1388 
1389       if(port->port_value_type == G_TYPE_OBJECT){
1390 	port->port_value.ags_port_object = data;
1391       }else{
1392 	g_warning("ags_port.c: unknown type");
1393       }
1394     }
1395   }
1396 
1397   g_rec_mutex_unlock(port_mutex);
1398 }
1399 
1400 /**
1401  * ags_port_safe_write:
1402  * @port: an #AgsPort
1403  * @value: the #GValue containing data
1404  *
1405  * Perform safe write.
1406  *
1407  * Since: 3.0.0
1408  */
1409 void
ags_port_safe_write(AgsPort * port,GValue * value)1410 ags_port_safe_write(AgsPort *port, GValue *value)
1411 {
1412   g_return_if_fail(AGS_IS_PORT(port));
1413   g_object_ref(G_OBJECT(port));
1414   g_signal_emit(G_OBJECT(port),
1415 		port_signals[SAFE_WRITE], 0,
1416 		value);
1417   g_object_unref(G_OBJECT(port));
1418 }
1419 
1420 void
ags_port_safe_write_raw(AgsPort * port,GValue * value)1421 ags_port_safe_write_raw(AgsPort *port, GValue *value)
1422 {
1423   guint overall_size;
1424   gpointer data;
1425 
1426   GRecMutex *port_mutex;
1427 
1428   if(!AGS_IS_PORT(port)){
1429     return;
1430   }
1431 
1432   /* get port mutex */
1433   port_mutex = AGS_PORT_GET_OBJ_MUTEX(port);
1434 
1435   /* write raw */
1436   g_rec_mutex_lock(port_mutex);
1437 
1438   overall_size = port->port_value_length * port->port_value_size;
1439 
1440   if(!port->port_value_is_pointer){
1441     if(port->port_value_type == G_TYPE_BOOLEAN){
1442       port->port_value.ags_port_boolean = g_value_get_boolean(value);
1443     }else if(port->port_value_type == G_TYPE_INT64){
1444       port->port_value.ags_port_int = g_value_get_int64(value);
1445     }else if(port->port_value_type == G_TYPE_UINT64){
1446       port->port_value.ags_port_uint = g_value_get_uint64(value);
1447     }else if(port->port_value_type == G_TYPE_FLOAT){
1448       if((AGS_PORT_USE_LADSPA_FLOAT & (port->flags)) == 0){
1449 	port->port_value.ags_port_float = (gfloat) g_value_get_float(value);
1450       }else{
1451 	port->port_value.ags_port_ladspa = (LADSPA_Data) g_value_get_float(value);
1452       }
1453     }else if(port->port_value_type == G_TYPE_DOUBLE){
1454       port->port_value.ags_port_double = g_value_get_double(value);
1455     }else if(port->port_value_type == G_TYPE_POINTER){
1456       port->port_value.ags_port_pointer = g_value_get_pointer(value);
1457     }else if(port->port_value_type == G_TYPE_OBJECT){
1458       port->port_value.ags_port_object = g_value_get_object(value);
1459     }else{
1460       g_warning("ags_port.c: unknown type");
1461     }
1462   }else{
1463     data = g_value_get_pointer(value);
1464 
1465     if(port->port_value_type == G_TYPE_BOOLEAN){
1466       memcpy(port->port_value.ags_port_boolean_ptr, data, overall_size);
1467     }else if(port->port_value_type == G_TYPE_INT64){
1468       memcpy(port->port_value.ags_port_int_ptr, data, overall_size);
1469     }else if(port->port_value_type == G_TYPE_UINT64){
1470       memcpy(port->port_value.ags_port_uint_ptr, data, overall_size);
1471     }else if(port->port_value_type == G_TYPE_DOUBLE){
1472       memcpy(port->port_value.ags_port_double_ptr, data, overall_size);
1473     }else if(port->port_value_type == G_TYPE_POINTER){
1474       port->port_value.ags_port_pointer = data;
1475     }else{
1476       data = g_value_get_object(value);
1477 
1478       if(port->port_value_type == G_TYPE_OBJECT){
1479 	port->port_value.ags_port_object = data;
1480       }else{
1481 	g_warning("ags_port.c: unknown type");
1482       }
1483     }
1484   }
1485 
1486   g_rec_mutex_unlock(port_mutex);
1487 }
1488 
1489 void
ags_port_real_safe_get_property(AgsPort * port,gchar * property_name,GValue * value)1490 ags_port_real_safe_get_property(AgsPort *port, gchar *property_name, GValue *value)
1491 {
1492   GRecMutex *port_mutex;
1493 
1494   /* get port mutex */
1495   port_mutex = AGS_PORT_GET_OBJ_MUTEX(port);
1496 
1497   /* get property */
1498   g_rec_mutex_lock(port_mutex);
1499 
1500   g_object_get_property(port->port_value.ags_port_object,
1501 			property_name,
1502 			value);
1503 
1504   g_rec_mutex_unlock(port_mutex);
1505 }
1506 
1507 /**
1508  * ags_port_safe_get_property:
1509  * @port: an #AgsPort
1510  * @property_name: the property's name
1511  * @value: the #GValue to store the result
1512  *
1513  * Perform safe get property.
1514  *
1515  * Since: 3.0.0
1516  */
1517 void
ags_port_safe_get_property(AgsPort * port,gchar * property_name,GValue * value)1518 ags_port_safe_get_property(AgsPort *port, gchar *property_name, GValue *value)
1519 {
1520   g_return_if_fail(AGS_IS_PORT(port));
1521   g_object_ref(G_OBJECT(port));
1522   g_signal_emit(G_OBJECT(port),
1523 		port_signals[SAFE_GET_PROPERTY], 0,
1524 		property_name, value);
1525   g_object_unref(G_OBJECT(port));
1526 }
1527 
1528 void
ags_port_real_safe_set_property(AgsPort * port,gchar * property_name,GValue * value)1529 ags_port_real_safe_set_property(AgsPort *port, gchar *property_name, GValue *value)
1530 {
1531   GRecMutex *port_mutex;
1532 
1533   /* get port mutex */
1534   port_mutex = AGS_PORT_GET_OBJ_MUTEX(port);
1535 
1536   /* set property */
1537   g_rec_mutex_lock(port_mutex);
1538 
1539   g_object_set_property(port->port_value.ags_port_object,
1540 			property_name,
1541 			value);
1542 
1543   g_rec_mutex_unlock(port_mutex);
1544 }
1545 
1546 /**
1547  * ags_port_safe_set_property:
1548  * @port: an #AgsPort
1549  * @property_name: the property's name
1550  * @value: the #GValue containing data
1551  *
1552  * Perform safe set property.
1553  *
1554  * Since: 3.0.0
1555  */
1556 void
ags_port_safe_set_property(AgsPort * port,gchar * property_name,GValue * value)1557 ags_port_safe_set_property(AgsPort *port, gchar *property_name, GValue *value)
1558 {
1559   g_return_if_fail(AGS_IS_PORT(port));
1560   g_object_ref(G_OBJECT(port));
1561   g_signal_emit(G_OBJECT(port),
1562 		port_signals[SAFE_SET_PROPERTY], 0,
1563 		property_name, value);
1564   g_object_unref(G_OBJECT(port));
1565 }
1566 
1567 /**
1568  * ags_port_find_specifier:
1569  * @port: (element-type AgsAudio.Port) (transfer none): the #GList-struct containing #AgsPort
1570  * @specifier: the recall specifier to match
1571  *
1572  * Retrieve port by specifier.
1573  *
1574  * Returns: (element-type AgsAudio.Port) (transfer none): Next matching #GList-struct or %NULL
1575  *
1576  * Since: 3.0.0
1577  */
1578 GList*
ags_port_find_specifier(GList * port,gchar * specifier)1579 ags_port_find_specifier(GList *port, gchar *specifier)
1580 {
1581   AgsPort *current_port;
1582 
1583   gboolean success;
1584 
1585   GRecMutex *port_mutex;
1586 
1587   while(port != NULL){
1588     current_port = port->data;
1589 
1590     /* get port mutex */
1591     port_mutex = AGS_PORT_GET_OBJ_MUTEX(current_port);
1592 
1593     /* check specifier */
1594     g_rec_mutex_lock(port_mutex);
1595 
1596     success = (!g_strcmp0(current_port->specifier,
1597 			  specifier)) ? TRUE: FALSE;
1598 
1599     g_rec_mutex_unlock(port_mutex);
1600 
1601     if(success){
1602       return(port);
1603     }
1604 
1605     port = port->next;
1606   }
1607 
1608   return(NULL);
1609 }
1610 
1611 /**
1612  * ags_port_add_automation:
1613  * @port: the #AgsPort
1614  * @automation: the #AgsAutomation
1615  *
1616  * Adds an automation.
1617  *
1618  * Since: 3.0.0
1619  */
1620 void
ags_port_add_automation(AgsPort * port,GObject * automation)1621 ags_port_add_automation(AgsPort *port, GObject *automation)
1622 {
1623   GRecMutex *port_mutex;
1624 
1625   if(!AGS_IS_PORT(port) ||
1626      !AGS_IS_AUTOMATION(automation)){
1627     return;
1628   }
1629 
1630   /* get port mutex */
1631   port_mutex = AGS_PORT_GET_OBJ_MUTEX(port);
1632 
1633   /* add recall id */
1634   g_rec_mutex_lock(port_mutex);
1635 
1636   if(g_list_find(port->automation,
1637 		 automation) == NULL){
1638     g_object_ref(automation);
1639     port->automation = ags_automation_add(port->automation,
1640 					  (AgsAutomation *) automation);
1641 
1642     g_object_set(automation,
1643 		 "port", port,
1644 		 NULL);
1645   }
1646 
1647   g_rec_mutex_unlock(port_mutex);
1648 }
1649 
1650 /**
1651  * ags_port_remove_automation:
1652  * @port: the #AgsPort
1653  * @automation: the #AgsAutomation
1654  *
1655  * Removes an automation.
1656  *
1657  * Since: 3.0.0
1658  */
1659 void
ags_port_remove_automation(AgsPort * port,GObject * automation)1660 ags_port_remove_automation(AgsPort *port, GObject *automation)
1661 {
1662   GRecMutex *port_mutex;
1663 
1664   if(!AGS_IS_PORT(port) ||
1665      !AGS_IS_AUTOMATION(automation)){
1666     return;
1667   }
1668 
1669   /* get port mutex */
1670   port_mutex = AGS_PORT_GET_OBJ_MUTEX(port);
1671 
1672   /* remove automation */
1673   g_rec_mutex_lock(port_mutex);
1674 
1675   if(g_list_find(port->automation,
1676 		 automation) != NULL){
1677     port->automation = g_list_remove(port->automation,
1678 				      automation);
1679 
1680     g_object_set(automation,
1681 		 "port", NULL,
1682 		 NULL);
1683 
1684     g_object_unref(automation);
1685   }
1686 
1687   g_rec_mutex_unlock(port_mutex);
1688 }
1689 
1690 /**
1691  * ags_port_new:
1692  *
1693  * Creates an #AgsPort.
1694  *
1695  * Returns: a new #AgsPort.
1696  *
1697  * Since: 3.0.0
1698  */
1699 AgsPort*
ags_port_new()1700 ags_port_new()
1701 {
1702   AgsPort *port;
1703 
1704   port = (AgsPort *) g_object_new(AGS_TYPE_PORT,
1705 				  NULL);
1706 
1707   return(port);
1708 }
1709