1 /* GSequencer - Advanced GTK Sequencer
2 * Copyright (C) 2005-2021 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/X/ags_line_member.h>
21 #include <ags/X/ags_line_member_callbacks.h>
22
23 #include <ags/X/ags_ui_provider.h>
24 #include <ags/X/ags_window.h>
25 #include <ags/X/ags_machine.h>
26 #include <ags/X/ags_pad.h>
27 #include <ags/X/ags_line.h>
28 #include <ags/X/ags_effect_pad.h>
29 #include <ags/X/ags_effect_line.h>
30
31 #include <ags/i18n.h>
32
33 void ags_line_member_class_init(AgsLineMemberClass *line_member);
34 void ags_line_member_connectable_interface_init(AgsConnectableInterface *connectable);
35 void ags_line_member_init(AgsLineMember *line_member);
36 void ags_line_member_set_property(GObject *gobject,
37 guint prop_id,
38 const GValue *value,
39 GParamSpec *param_spec);
40 void ags_line_member_get_property(GObject *gobject,
41 guint prop_id,
42 GValue *value,
43 GParamSpec *param_spec);
44 void ags_line_member_finalize(GObject *gobject);
45
46 void ags_line_member_connect(AgsConnectable *connectable);
47 void ags_line_member_disconnect(AgsConnectable *connectable);
48
49 void ags_line_member_real_change_port(AgsLineMember *line_member,
50 gpointer port_data);
51
52 AgsPort* ags_line_member_find_specifier(GList *recall,
53 gchar *specifier);
54
55 GList* ags_line_member_real_find_port(AgsLineMember *line_member);
56
57
58 /**
59 * SECTION:ags_line_member
60 * @short_description: Modify assigned recall's port
61 * @title: AgsLineMember
62 * @section_id:
63 * @include: ags/X/ags_line_member.h
64 *
65 * #AgsLineMember is a composite widget to modify ports of recalls. A line member
66 * controls only one specific port of a recall but distinguishes between simple/complex
67 * recall. It is generally packed into a #AgsLine.
68 */
69
70 enum{
71 CHANGE_PORT,
72 FIND_PORT,
73 LAST_SIGNAL,
74 };
75
76 enum{
77 PROP_0,
78 PROP_WIDGET_TYPE,
79 PROP_WIDGET_ORIENTATION,
80 PROP_WIDGET_LABEL,
81 PROP_PLAY_CONTAINER,
82 PROP_RECALL_CONTAINER,
83 PROP_PLUGIN_NAME,
84 PROP_FILENAME,
85 PROP_EFFECT,
86 PROP_SPECIFIER,
87 PROP_CONTROL_PORT,
88 PROP_SCALE_PRECISION,
89 PROP_STEP_COUNT,
90 PROP_CONVERSION,
91 PROP_PORT,
92 PROP_PORT_DATA,
93 PROP_RECALL_PORT,
94 PROP_RECALL_PORT_DATA,
95 PROP_TASK_TYPE,
96 };
97
98 static gpointer ags_line_member_parent_class = NULL;
99 static guint line_member_signals[LAST_SIGNAL];
100
101 GType
ags_line_member_get_type(void)102 ags_line_member_get_type(void)
103 {
104 static volatile gsize g_define_type_id__volatile = 0;
105
106 if(g_once_init_enter (&g_define_type_id__volatile)){
107 GType ags_type_line_member = 0;
108
109 static const GTypeInfo ags_line_member_info = {
110 sizeof(AgsLineMemberClass),
111 NULL, /* base_init */
112 NULL, /* base_finalize */
113 (GClassInitFunc) ags_line_member_class_init,
114 NULL, /* class_finalize */
115 NULL, /* class_data */
116 sizeof(AgsLineMember),
117 0, /* n_preallocs */
118 (GInstanceInitFunc) ags_line_member_init,
119 };
120
121 static const GInterfaceInfo ags_connectable_interface_info = {
122 (GInterfaceInitFunc) ags_line_member_connectable_interface_init,
123 NULL, /* interface_finalize */
124 NULL, /* interface_data */
125 };
126
127 ags_type_line_member = g_type_register_static(GTK_TYPE_FRAME,
128 "AgsLineMember", &ags_line_member_info,
129 0);
130
131 g_type_add_interface_static(ags_type_line_member,
132 AGS_TYPE_CONNECTABLE,
133 &ags_connectable_interface_info);
134
135 g_once_init_leave(&g_define_type_id__volatile, ags_type_line_member);
136 }
137
138 return g_define_type_id__volatile;
139 }
140
141 void
ags_line_member_class_init(AgsLineMemberClass * line_member)142 ags_line_member_class_init(AgsLineMemberClass *line_member)
143 {
144 GObjectClass *gobject;
145 GParamSpec *param_spec;
146
147 ags_line_member_parent_class = g_type_class_peek_parent(line_member);
148
149 /* GObjectClass */
150 gobject = G_OBJECT_CLASS(line_member);
151
152 gobject->set_property = ags_line_member_set_property;
153 gobject->get_property = ags_line_member_get_property;
154
155 gobject->finalize = ags_line_member_finalize;
156
157 /* properties */
158 /**
159 * AgsLineMember:widget-type:
160 *
161 * The widget type to instantiate and use as control.
162 *
163 * Since: 3.0.0
164 */
165 param_spec = g_param_spec_ulong("widget-type",
166 i18n_pspec("widget type of line member"),
167 i18n_pspec("The widget type this line member packs"),
168 0, G_MAXULONG,
169 G_TYPE_NONE,
170 G_PARAM_READABLE | G_PARAM_WRITABLE);
171 g_object_class_install_property(gobject,
172 PROP_WIDGET_TYPE,
173 param_spec);
174
175 /**
176 * AgsLineMember:widget-orientation:
177 *
178 * The widget orientation.
179 *
180 * Since: 3.8.0
181 */
182 param_spec = g_param_spec_uint("widget-orientation",
183 i18n_pspec("widget orientation"),
184 i18n_pspec("widget orientation"),
185 0, G_MAXUINT,
186 GTK_ORIENTATION_VERTICAL,
187 G_PARAM_READABLE | G_PARAM_WRITABLE);
188 g_object_class_install_property(gobject,
189 PROP_WIDGET_ORIENTATION,
190 param_spec);
191
192 /**
193 * AgsLineMember:widget-label:
194 *
195 * The widget's label to use.
196 *
197 * Since: 3.0.0
198 */
199 param_spec = g_param_spec_string("widget-label",
200 i18n_pspec("label to display"),
201 i18n_pspec("The label to display"),
202 NULL,
203 G_PARAM_READABLE | G_PARAM_WRITABLE);
204 g_object_class_install_property(gobject,
205 PROP_WIDGET_LABEL,
206 param_spec);
207
208 /**
209 * AgsLineMember:play-container:
210 *
211 * The play context recall container.
212 *
213 * Since: 3.3.0
214 */
215 param_spec = g_param_spec_object("play-container",
216 i18n_pspec("play container"),
217 i18n_pspec("The play context recall container"),
218 AGS_TYPE_RECALL_CONTAINER,
219 G_PARAM_READABLE | G_PARAM_WRITABLE);
220 g_object_class_install_property(gobject,
221 PROP_PLAY_CONTAINER,
222 param_spec);
223
224 /**
225 * AgsLineMember:recall-container:
226 *
227 * The recall context recall container.
228 *
229 * Since: 3.3.0
230 */
231 param_spec = g_param_spec_object("recall-container",
232 i18n_pspec("recall container"),
233 i18n_pspec("The recall context recall container"),
234 AGS_TYPE_RECALL_CONTAINER,
235 G_PARAM_READABLE | G_PARAM_WRITABLE);
236 g_object_class_install_property(gobject,
237 PROP_RECALL_CONTAINER,
238 param_spec);
239
240 /**
241 * AgsLineMember:plugin-name:
242 *
243 * The plugin name of the recall to use.
244 *
245 * Since: 3.0.0
246 */
247 param_spec = g_param_spec_string("plugin-name",
248 i18n_pspec("plugin name to control"),
249 i18n_pspec("The plugin's name to control"),
250 NULL,
251 G_PARAM_READABLE | G_PARAM_WRITABLE);
252 g_object_class_install_property(gobject,
253 PROP_PLUGIN_NAME,
254 param_spec);
255
256 /**
257 * AgsLineMember:filename:
258 *
259 * The plugin filename of the recall to apply.
260 *
261 * Since: 3.0.0
262 */
263 param_spec = g_param_spec_string("filename",
264 i18n_pspec("the filename"),
265 i18n_pspec("The filename of the plugin"),
266 NULL,
267 G_PARAM_READABLE | G_PARAM_WRITABLE);
268 g_object_class_install_property(gobject,
269 PROP_FILENAME,
270 param_spec);
271
272 /**
273 * AgsLineMember:effect:
274 *
275 * The plugin effect of the recall to apply.
276 *
277 * Since: 3.0.0
278 */
279 param_spec = g_param_spec_string("effect",
280 i18n_pspec("the effect"),
281 i18n_pspec("The effect of the plugin"),
282 NULL,
283 G_PARAM_READABLE | G_PARAM_WRITABLE);
284 g_object_class_install_property(gobject,
285 PROP_EFFECT,
286 param_spec);
287
288 /**
289 * AgsLineMember:specifier:
290 *
291 * The plugin specifier of the recall to apply.
292 *
293 * Since: 3.0.0
294 */
295 param_spec = g_param_spec_string("specifier",
296 i18n_pspec("port specifier"),
297 i18n_pspec("The specifier of the port"),
298 NULL,
299 G_PARAM_READABLE | G_PARAM_WRITABLE);
300 g_object_class_install_property(gobject,
301 PROP_SPECIFIER,
302 param_spec);
303
304 /**
305 * AgsLineMember:control-port:
306 *
307 * The control port of the recall.
308 *
309 * Since: 3.0.0
310 */
311 param_spec = g_param_spec_string("control-port",
312 i18n_pspec("control port index"),
313 i18n_pspec("The index of the port to control"),
314 NULL,
315 G_PARAM_READABLE | G_PARAM_WRITABLE);
316 g_object_class_install_property(gobject,
317 PROP_CONTROL_PORT,
318 param_spec);
319
320 /**
321 * AgsLineMember:scale-precision:
322 *
323 * If line member has integer ports, this is the number of steps.
324 *
325 * Since: 3.0.0
326 */
327 param_spec = g_param_spec_uint("scale-precision",
328 i18n_pspec("scale precision of line members port"),
329 i18n_pspec("The scale precision this line members port has"),
330 0,
331 G_MAXUINT,
332 (guint) AGS_DIAL_DEFAULT_PRECISION,
333 G_PARAM_READABLE | G_PARAM_WRITABLE);
334 g_object_class_install_property(gobject,
335 PROP_SCALE_PRECISION,
336 param_spec);
337
338 /**
339 * AgsLineMember:step-count:
340 *
341 * If line member has logarithmic ports, this is the number of step count.
342 *
343 * Since: 3.0.0
344 */
345 param_spec = g_param_spec_double("step-count",
346 i18n_pspec("step count of line members port"),
347 i18n_pspec("The step count this line members port has"),
348 0.0,
349 G_MAXDOUBLE,
350 AGS_LADSPA_CONVERSION_DEFAULT_STEP_COUNT,
351 G_PARAM_READABLE | G_PARAM_WRITABLE);
352 g_object_class_install_property(gobject,
353 PROP_STEP_COUNT,
354 param_spec);
355
356 /**
357 * AgsLineMember:conversion:
358 *
359 * The conversion of plugin.
360 *
361 * Since: 3.0.0
362 */
363 param_spec = g_param_spec_object("conversion",
364 i18n_pspec("conversion to apply"),
365 i18n_pspec("The conversion to apply"),
366 AGS_TYPE_CONVERSION,
367 G_PARAM_READABLE | G_PARAM_WRITABLE);
368 g_object_class_install_property(gobject,
369 PROP_CONVERSION,
370 param_spec);
371
372 /**
373 * AgsLineMember:port:
374 *
375 * The matching simple port of plugin name and specifier.
376 *
377 * Since: 3.0.0
378 */
379 param_spec = g_param_spec_object("port",
380 i18n_pspec("port to apply"),
381 i18n_pspec("The port to apply"),
382 AGS_TYPE_PORT,
383 G_PARAM_READABLE | G_PARAM_WRITABLE);
384 g_object_class_install_property(gobject,
385 PROP_PORT,
386 param_spec);
387
388 /**
389 * AgsLineMember:port-data:
390 *
391 * The port data to apply.
392 *
393 * Since: 3.0.0
394 */
395 param_spec = g_param_spec_pointer("port-data",
396 i18n_pspec("port data"),
397 i18n_pspec("The port data"),
398 G_PARAM_READABLE | G_PARAM_WRITABLE);
399 g_object_class_install_property(gobject,
400 PROP_PORT_DATA,
401 param_spec);
402
403 /**
404 * AgsLineMember:recall-port:
405 *
406 * The matching complex port of plugin name and specifier.
407 *
408 * Since: 3.0.0
409 */
410 param_spec = g_param_spec_object("recall-port",
411 i18n_pspec("recall port to apply"),
412 i18n_pspec("The recall port to apply"),
413 AGS_TYPE_PORT,
414 G_PARAM_READABLE | G_PARAM_WRITABLE);
415 g_object_class_install_property(gobject,
416 PROP_RECALL_PORT,
417 param_spec);
418
419 /**
420 * AgsLineMember:recall-port-data:
421 *
422 * The complex port data to apply.
423 *
424 * Since: 3.0.0
425 */
426 param_spec = g_param_spec_pointer("recall-port-data",
427 i18n_pspec("recall port data"),
428 i18n_pspec("The recall port data"),
429 G_PARAM_READABLE | G_PARAM_WRITABLE);
430 g_object_class_install_property(gobject,
431 PROP_RECALL_PORT_DATA,
432 param_spec);
433
434 /**
435 * AgsLineMember:task-type:
436 *
437 * The task type to apply the port.
438 *
439 * Since: 3.0.0
440 */
441 param_spec = g_param_spec_ulong("task-type",
442 i18n_pspec("task type to apply"),
443 i18n_pspec("The task type to apply the port"),
444 0, G_MAXULONG,
445 G_TYPE_NONE,
446 G_PARAM_READABLE | G_PARAM_WRITABLE);
447 g_object_class_install_property(gobject,
448 PROP_TASK_TYPE,
449 param_spec);
450
451 /* AgsLineMember */
452 line_member->change_port = ags_line_member_real_change_port;
453 line_member->find_port = ags_line_member_real_find_port;
454
455 /* signals */
456 /**
457 * AgsLineMember::change-port:
458 * @line_member: the #AgsLineMember
459 * @port_data: the port's data
460 *
461 * The ::change-port signal notifies modified port.
462 *
463 * Since: 3.0.0
464 */
465 line_member_signals[CHANGE_PORT] =
466 g_signal_new("change-port",
467 G_TYPE_FROM_CLASS(line_member),
468 G_SIGNAL_RUN_LAST,
469 G_STRUCT_OFFSET(AgsLineMemberClass, change_port),
470 NULL, NULL,
471 g_cclosure_marshal_VOID__POINTER,
472 G_TYPE_NONE, 1,
473 G_TYPE_POINTER);
474
475 /**
476 * AgsLine_Member::find-port:
477 * @line_member: the #AgsLineMember to resize
478 *
479 * The ::find-port retrieves all associated ports
480 *
481 * Returns: a #GList-struct with associated ports
482 *
483 * Since: 3.0.0
484 */
485 line_member_signals[FIND_PORT] =
486 g_signal_new("find-port",
487 G_TYPE_FROM_CLASS(line_member),
488 G_SIGNAL_RUN_LAST,
489 G_STRUCT_OFFSET(AgsLineMemberClass, find_port),
490 NULL, NULL,
491 ags_cclosure_marshal_POINTER__VOID,
492 G_TYPE_POINTER, 0);
493 }
494
495 void
ags_line_member_connectable_interface_init(AgsConnectableInterface * connectable)496 ags_line_member_connectable_interface_init(AgsConnectableInterface *connectable)
497 {
498 connectable->connect = ags_line_member_connect;
499 connectable->disconnect = ags_line_member_disconnect;
500 }
501
502 void
ags_line_member_init(AgsLineMember * line_member)503 ags_line_member_init(AgsLineMember *line_member)
504 {
505 AgsDial *dial;
506
507 AgsApplicationContext *application_context;
508
509 gdouble gui_scale_factor;
510
511 application_context = ags_application_context_get_instance();
512
513 g_signal_connect_after((GObject *) line_member, "parent_set",
514 G_CALLBACK(ags_line_member_parent_set_callback), (gpointer) line_member);
515
516 line_member->flags = (AGS_LINE_MEMBER_RESET_BY_ATOMIC |
517 AGS_LINE_MEMBER_APPLY_RECALL);
518 line_member->port_flags = 0;
519
520 line_member->widget_type = AGS_TYPE_DIAL;
521 line_member->widget_orientation = GTK_ORIENTATION_VERTICAL;
522 dial = (AgsDial *) g_object_new(AGS_TYPE_DIAL,
523 "adjustment", gtk_adjustment_new(0.0, 0.0, 1.0, 0.1, 0.1, 0.0),
524 NULL);
525
526 /* scale factor */
527 gui_scale_factor = ags_ui_provider_get_gui_scale_factor(AGS_UI_PROVIDER(application_context));
528
529 g_object_set(dial,
530 "radius", (guint) (gui_scale_factor * AGS_DIAL_DEFAULT_RADIUS),
531 "font-size", (guint) (gui_scale_factor * AGS_DIAL_DEFAULT_FONT_SIZE),
532 "button-width", (gint) (gui_scale_factor * AGS_DIAL_DEFAULT_BUTTON_WIDTH),
533 "button-height", (gint) (gui_scale_factor * AGS_DIAL_DEFAULT_BUTTON_HEIGHT),
534 NULL);
535
536 gtk_container_add(GTK_CONTAINER(line_member),
537 (GtkWidget *) dial);
538
539 line_member->widget_label = NULL;
540
541 line_member->play_container = NULL;
542 line_member->recall_container = NULL;
543
544 line_member->plugin_name = NULL;
545
546 line_member->filename = NULL;
547 line_member->effect = NULL;
548
549 line_member->specifier = NULL;
550
551 line_member->control_port = NULL;
552
553 line_member->scale_precision = AGS_DIAL_DEFAULT_PRECISION;
554 line_member->step_count = AGS_LADSPA_CONVERSION_DEFAULT_STEP_COUNT;
555
556 line_member->conversion = NULL;
557
558 line_member->port = NULL;
559 line_member->port_data = NULL;
560 line_member->active = FALSE;
561
562 line_member->recall_port = NULL;
563 line_member->recall_port_data = NULL;
564 line_member->recall_active = FALSE;
565
566 line_member->task_type = G_TYPE_NONE;
567 }
568
569 void
ags_line_member_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)570 ags_line_member_set_property(GObject *gobject,
571 guint prop_id,
572 const GValue *value,
573 GParamSpec *param_spec)
574 {
575 AgsLineMember *line_member;
576
577 line_member = AGS_LINE_MEMBER(gobject);
578
579 switch(prop_id){
580 case PROP_WIDGET_TYPE:
581 {
582 GtkWidget *child, *new_child;
583
584 GtkAdjustment *adjustment;
585
586 AgsApplicationContext *application_context;
587
588 GType widget_type;
589
590 gdouble gui_scale_factor;
591 gdouble lower_value, upper_value;
592 gdouble current_value;
593 gboolean active;
594
595 //TODO:JK: verify me
596 widget_type = g_value_get_ulong(value);
597
598 if(widget_type == line_member->widget_type){
599 return;
600 }
601
602 application_context = ags_application_context_get_instance();
603
604 child = gtk_bin_get_child(GTK_BIN(line_member));
605
606 /* preserver previous range */
607 adjustment = NULL;
608 active = FALSE;
609
610 if(GTK_IS_RANGE(child)){
611 adjustment = gtk_range_get_adjustment(GTK_RANGE(child));
612 }else if(GTK_IS_SPIN_BUTTON(child)){
613 adjustment = gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(child));
614 }else if(AGS_IS_DIAL(child)){
615 adjustment = AGS_DIAL(child)->adjustment;
616 }else if(GTK_IS_TOGGLE_BUTTON(child)){
617 active = gtk_toggle_button_get_active((GtkToggleButton *) child);
618 }
619
620 lower_value = 0.0;
621 upper_value = 0.0;
622
623 current_value = 0.0;
624
625 if(adjustment != NULL){
626 lower_value = gtk_adjustment_get_lower(adjustment);
627 upper_value = gtk_adjustment_get_upper(adjustment);
628
629 current_value = gtk_adjustment_get_value(adjustment);
630 }
631
632 /* destroy old */
633 if(child != NULL){
634 gtk_widget_destroy(child);
635 }
636
637 line_member->widget_type = widget_type;
638 new_child = (GtkWidget *) g_object_new(widget_type,
639 NULL);
640
641 /* scale factor */
642 gui_scale_factor = ags_ui_provider_get_gui_scale_factor(AGS_UI_PROVIDER(application_context));
643
644 if(AGS_IS_DIAL(new_child)){
645 g_object_set(new_child,
646 "radius", (guint) (gui_scale_factor * AGS_DIAL_DEFAULT_RADIUS),
647 "font-size", (guint) (gui_scale_factor * AGS_DIAL_DEFAULT_FONT_SIZE),
648 "button-width", (gint) (gui_scale_factor * AGS_DIAL_DEFAULT_BUTTON_WIDTH),
649 "button-height", (gint) (gui_scale_factor * AGS_DIAL_DEFAULT_BUTTON_HEIGHT),
650 NULL);
651 }else if(GTK_IS_SCALE(new_child)){
652 guint widget_orientation;
653
654 widget_orientation = GTK_ORIENTATION_VERTICAL;
655
656 g_object_get(line_member,
657 "widget-orientation", &widget_orientation,
658 NULL);
659
660 gtk_orientable_set_orientation(GTK_ORIENTABLE(new_child),
661 widget_orientation);
662
663 if(widget_orientation == GTK_ORIENTATION_VERTICAL){
664 gtk_widget_set_size_request(new_child,
665 gui_scale_factor * 16, gui_scale_factor * 100);
666 }else{
667 gtk_widget_set_size_request(new_child,
668 gui_scale_factor * 100, gui_scale_factor * 16);
669 }
670 }else if(AGS_IS_VINDICATOR(new_child)){
671 g_object_set(new_child,
672 "segment-width", (guint) (gui_scale_factor * AGS_VINDICATOR_DEFAULT_SEGMENT_WIDTH),
673 "segment-height", (guint) (gui_scale_factor * AGS_VINDICATOR_DEFAULT_SEGMENT_HEIGHT),
674 "segment-padding", (guint) (gui_scale_factor * AGS_INDICATOR_DEFAULT_SEGMENT_PADDING),
675 NULL);
676
677 //FIXME:JK: make indicator orientable
678 }else if(AGS_IS_HINDICATOR(new_child)){
679 g_object_set(new_child,
680 "segment-width", (guint) (gui_scale_factor * AGS_HINDICATOR_DEFAULT_SEGMENT_WIDTH),
681 "segment-height", (guint) (gui_scale_factor * AGS_HINDICATOR_DEFAULT_SEGMENT_HEIGHT),
682 "segment-padding", (guint) (gui_scale_factor * AGS_INDICATOR_DEFAULT_SEGMENT_PADDING),
683 NULL);
684
685 //FIXME:JK: make indicator orientable
686 }
687
688 gtk_widget_queue_resize_no_redraw(new_child);
689 gtk_widget_queue_draw(new_child);
690
691 /* set range */
692 if(GTK_IS_RANGE(new_child)){
693 GtkAdjustment *new_adjustment;
694
695 new_adjustment = gtk_range_get_adjustment(GTK_RANGE(new_child));
696
697 gtk_adjustment_set_lower(new_adjustment,
698 lower_value);
699 gtk_adjustment_set_upper(new_adjustment,
700 upper_value);
701
702 gtk_adjustment_set_value(new_adjustment,
703 current_value);
704 }else if(GTK_IS_SPIN_BUTTON(new_child)){
705 GtkAdjustment *new_adjustment;
706
707 new_adjustment = gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(new_child));
708
709 gtk_adjustment_set_lower(new_adjustment,
710 lower_value);
711 gtk_adjustment_set_upper(new_adjustment,
712 upper_value);
713
714 gtk_adjustment_set_value(new_adjustment,
715 current_value);
716 }else if(AGS_IS_DIAL(new_child)){
717 GtkAdjustment *new_adjustment;
718
719 new_adjustment = AGS_DIAL(new_child)->adjustment;
720
721 gtk_adjustment_set_lower(new_adjustment,
722 lower_value);
723 gtk_adjustment_set_upper(new_adjustment,
724 upper_value);
725
726 gtk_adjustment_set_value(new_adjustment,
727 current_value);
728
729 gtk_widget_queue_draw((GtkWidget *) new_child);
730 }else if(GTK_IS_TOGGLE_BUTTON(new_child)){
731 gtk_toggle_button_set_active((GtkToggleButton *) new_child,
732 active);
733 }else{
734 if(!(AGS_IS_INDICATOR(new_child) ||
735 AGS_IS_LED(new_child))){
736 g_warning("ags_line_member_set_property() - unknown child type %s", g_type_name(widget_type));
737 }
738 }
739
740 /* add */
741 gtk_container_add(GTK_CONTAINER(line_member),
742 new_child);
743 }
744 break;
745 case PROP_WIDGET_ORIENTATION:
746 {
747 GtkWidget *child;
748
749 AgsApplicationContext *application_context;
750
751 gdouble gui_scale_factor;
752 guint widget_orientation;
753
754 widget_orientation = g_value_get_uint(value);
755
756 line_member->widget_orientation = widget_orientation;
757
758 application_context = ags_application_context_get_instance();
759
760 /* scale factor */
761 gui_scale_factor = ags_ui_provider_get_gui_scale_factor(AGS_UI_PROVIDER(application_context));
762
763 child = gtk_bin_get_child(GTK_BIN(line_member));
764
765 if(GTK_IS_SCALE(child)){
766 gtk_orientable_set_orientation(GTK_ORIENTABLE(child),
767 widget_orientation);
768
769 if(widget_orientation == GTK_ORIENTATION_VERTICAL){
770 gtk_widget_set_size_request(child,
771 gui_scale_factor * 16, gui_scale_factor * 100);
772 }else{
773 gtk_widget_set_size_request(child,
774 gui_scale_factor * 100, gui_scale_factor * 16);
775 }
776 }else if(AGS_IS_INDICATOR(child)){
777 gtk_orientable_set_orientation(GTK_ORIENTABLE(child),
778 widget_orientation);
779
780 //FIXME:JK: make indicator orientable
781 }
782 }
783 break;
784 case PROP_WIDGET_LABEL:
785 {
786 gchar *label;
787
788 label = g_value_get_string(value);
789
790 if(label == line_member->widget_label){
791 return;
792 }
793
794 if(line_member->widget_label != NULL){
795 g_free(line_member->widget_label);
796 }
797
798 line_member->widget_label = g_strdup(label);
799 ags_line_member_set_label(line_member, line_member->widget_label);
800 }
801 break;
802 case PROP_PLAY_CONTAINER:
803 {
804 AgsRecallContainer *play_container;
805
806 play_container = (AgsRecallContainer *) g_value_get_object(value);
807
808 if(play_container == line_member->play_container){
809 return;
810 }
811
812 if(line_member->play_container != NULL){
813 g_object_unref(line_member->play_container);
814 }
815
816 if(play_container != NULL){
817 g_object_ref(play_container);
818 }
819
820 line_member->play_container = play_container;
821 }
822 break;
823 case PROP_RECALL_CONTAINER:
824 {
825 AgsRecallContainer *recall_container;
826
827 recall_container = (AgsRecallContainer *) g_value_get_object(value);
828
829 if(recall_container == line_member->recall_container){
830 return;
831 }
832
833 if(line_member->recall_container != NULL){
834 g_object_unref(line_member->recall_container);
835 }
836
837 if(recall_container != NULL){
838 g_object_ref(recall_container);
839 }
840
841 line_member->recall_container = recall_container;
842 }
843 break;
844 case PROP_PLUGIN_NAME:
845 {
846 gchar *plugin_name;
847
848 plugin_name = g_value_get_string(value);
849
850 if(plugin_name == line_member->plugin_name){
851 return;
852 }
853
854 line_member->plugin_name = g_strdup(plugin_name);
855 }
856 break;
857 case PROP_FILENAME:
858 {
859 gchar *filename;
860
861 filename = g_value_get_string(value);
862
863 if(filename == line_member->filename){
864 return;
865 }
866
867 if(line_member->filename != NULL){
868 g_free(line_member->filename);
869 }
870
871 if(filename != NULL){
872 if(!g_file_test(filename,
873 G_FILE_TEST_EXISTS)){
874 AgsWindow *window;
875
876 window = (AgsWindow *) gtk_widget_get_toplevel((GtkWidget *) line_member);
877
878 ags_window_show_error(window,
879 g_strdup_printf("Plugin file not present %s",
880 filename));
881 }
882 }
883
884 line_member->filename = g_strdup(filename);
885 }
886 break;
887 case PROP_EFFECT:
888 {
889 gchar *effect;
890
891 effect = g_value_get_string(value);
892
893 if(effect == line_member->effect){
894 return;
895 }
896
897 line_member->effect = g_strdup(effect);
898 }
899 break;
900 case PROP_SPECIFIER:
901 {
902 gchar *specifier;
903
904 specifier = g_value_get_string(value);
905
906 if(specifier == line_member->specifier){
907 return;
908 }
909
910 line_member->specifier = g_strdup(specifier);
911 }
912 break;
913 case PROP_CONTROL_PORT:
914 {
915 gchar *control_port;
916
917 control_port = g_value_get_string(value);
918
919 if(control_port == line_member->control_port){
920 return;
921 }
922
923 line_member->control_port = g_strdup(control_port);
924 }
925 break;
926 case PROP_SCALE_PRECISION:
927 {
928 GtkWidget *child;
929
930 guint scale_precision;
931
932 scale_precision = g_value_get_uint(value);
933
934 line_member->scale_precision = scale_precision;
935 child = gtk_bin_get_child(GTK_BIN(line_member));
936
937 if(AGS_IS_DIAL(child)){
938 g_object_set(child,
939 "scale-precision", scale_precision,
940 NULL);
941 }
942 }
943 break;
944 case PROP_STEP_COUNT:
945 {
946 gdouble step_count;
947
948 step_count = g_value_get_double(value);
949
950 line_member->step_count = step_count;
951 }
952 break;
953 case PROP_CONVERSION:
954 {
955 AgsConversion *conversion;
956
957 conversion = g_value_get_object(value);
958
959 if(conversion == line_member->conversion){
960 return;
961 }
962
963 if(line_member->conversion != NULL){
964 g_object_unref(line_member->conversion);
965 }
966
967 if(conversion != NULL){
968 g_object_ref(conversion);
969 }
970
971 line_member->conversion = conversion;
972 }
973 break;
974 case PROP_PORT:
975 {
976 AgsPort *port;
977
978 port = g_value_get_object(value);
979
980 if(port == line_member->port){
981 return;
982 }
983
984 if(line_member->port != NULL){
985 g_object_unref(line_member->port);
986 }
987
988 if(port != NULL){
989 g_object_ref(port);
990
991 if((AGS_PORT_INFINITE_RANGE & (port->flags)) != 0){
992 GtkWidget *child;
993
994 child = gtk_bin_get_child(GTK_BIN(line_member));
995
996 //TODO:JK: add more orientations
997
998 if(AGS_IS_DIAL(child)){
999 AGS_DIAL(child)->flags |= AGS_DIAL_SEEMLESS_MODE;
1000 }
1001 }
1002 }
1003
1004 line_member->port = port;
1005 }
1006 break;
1007 case PROP_PORT_DATA:
1008 {
1009 gpointer port_data;
1010
1011 port_data = g_value_get_pointer(value);
1012
1013 if(port_data == line_member->port_data){
1014 return;
1015 }
1016
1017 line_member->port_data = port_data;
1018 }
1019 break;
1020 case PROP_RECALL_PORT:
1021 {
1022 AgsPort *port;
1023
1024 port = g_value_get_object(value);
1025
1026 if(port == line_member->recall_port){
1027 return;
1028 }
1029
1030 if(line_member->recall_port != NULL){
1031 g_object_unref(line_member->recall_port);
1032 }
1033
1034 if(port != NULL){
1035 g_object_ref(port);
1036 }
1037
1038 line_member->recall_port = port;
1039 }
1040 break;
1041 case PROP_RECALL_PORT_DATA:
1042 {
1043 gpointer port_data;
1044
1045 port_data = g_value_get_pointer(value);
1046
1047 if(port_data == line_member->recall_port_data){
1048 return;
1049 }
1050
1051 line_member->recall_port_data = port_data;
1052 }
1053 break;
1054 case PROP_TASK_TYPE:
1055 {
1056 GType type;
1057
1058 type = g_value_get_ulong(value);
1059
1060 if(line_member->task_type == type){
1061 return;
1062 }
1063
1064 line_member->task_type = type;
1065 }
1066 break;
1067 default:
1068 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
1069 break;
1070 }
1071 }
1072
1073 void
ags_line_member_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)1074 ags_line_member_get_property(GObject *gobject,
1075 guint prop_id,
1076 GValue *value,
1077 GParamSpec *param_spec)
1078 {
1079 AgsLineMember *line_member;
1080
1081 line_member = AGS_LINE_MEMBER(gobject);
1082
1083 switch(prop_id){
1084 case PROP_WIDGET_TYPE:
1085 {
1086 g_value_set_ulong(value, line_member->widget_type);
1087 }
1088 break;
1089 case PROP_WIDGET_ORIENTATION:
1090 {
1091 g_value_set_uint(value, line_member->widget_orientation);
1092 }
1093 break;
1094 case PROP_WIDGET_LABEL:
1095 {
1096 g_value_set_string(value, line_member->widget_label);
1097 }
1098 break;
1099 case PROP_PLAY_CONTAINER:
1100 {
1101 g_value_set_object(value, line_member->play_container);
1102 }
1103 break;
1104 case PROP_RECALL_CONTAINER:
1105 {
1106 g_value_set_object(value, line_member->recall_container);
1107 }
1108 break;
1109 case PROP_PLUGIN_NAME:
1110 {
1111 g_value_set_string(value, line_member->plugin_name);
1112 }
1113 break;
1114 case PROP_FILENAME:
1115 {
1116 g_value_set_string(value, line_member->filename);
1117 }
1118 break;
1119 case PROP_EFFECT:
1120 {
1121 g_value_set_string(value, line_member->effect);
1122 }
1123 break;
1124 case PROP_SPECIFIER:
1125 {
1126 g_value_set_string(value, line_member->specifier);
1127 }
1128 break;
1129 case PROP_CONTROL_PORT:
1130 {
1131 g_value_set_string(value, line_member->control_port);
1132 }
1133 break;
1134 case PROP_SCALE_PRECISION:
1135 {
1136 g_value_set_uint(value, line_member->scale_precision);
1137 }
1138 break;
1139 case PROP_STEP_COUNT:
1140 {
1141 g_value_set_double(value, line_member->step_count);
1142 }
1143 break;
1144 case PROP_CONVERSION:
1145 {
1146 g_value_set_object(value, line_member->conversion);
1147 }
1148 break;
1149 case PROP_PORT:
1150 {
1151 g_value_set_object(value, line_member->port);
1152 }
1153 break;
1154 case PROP_PORT_DATA:
1155 {
1156 g_value_set_pointer(value, line_member->port_data);
1157 }
1158 break;
1159 case PROP_RECALL_PORT:
1160 {
1161 g_value_set_object(value, line_member->port);
1162 }
1163 break;
1164 case PROP_RECALL_PORT_DATA:
1165 {
1166 g_value_set_pointer(value, line_member->port_data);
1167 }
1168 break;
1169 case PROP_TASK_TYPE:
1170 {
1171 g_value_set_ulong(value, line_member->task_type);
1172 }
1173 break;
1174 default:
1175 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
1176 break;
1177 }
1178 }
1179
1180 void
ags_line_member_finalize(GObject * gobject)1181 ags_line_member_finalize(GObject *gobject)
1182 {
1183 AgsLineMember *line_member;
1184
1185 line_member = (AgsLineMember *) gobject;
1186
1187 g_free(line_member->widget_label);
1188
1189 if(line_member->play_container != NULL){
1190 g_object_unref(line_member->play_container);
1191 }
1192
1193 if(line_member->recall_container != NULL){
1194 g_object_unref(line_member->recall_container);
1195 }
1196
1197 g_free(line_member->plugin_name);
1198
1199 g_free(line_member->filename);
1200 g_free(line_member->effect);
1201
1202 g_free(line_member->specifier);
1203
1204 g_free(line_member->control_port);
1205
1206 if(line_member->conversion != NULL){
1207 g_object_unref(line_member->conversion);
1208 }
1209
1210 if(line_member->port != NULL){
1211 g_object_unref(line_member->port);
1212 }
1213
1214 if(line_member->recall_port != NULL){
1215 g_object_unref(line_member->recall_port);
1216 }
1217
1218 /* call parent */
1219 G_OBJECT_CLASS(ags_line_member_parent_class)->finalize(gobject);
1220 }
1221
1222 void
ags_line_member_connect(AgsConnectable * connectable)1223 ags_line_member_connect(AgsConnectable *connectable)
1224 {
1225 AgsLineMember *line_member;
1226 GtkWidget *control;
1227
1228 line_member = AGS_LINE_MEMBER(connectable);
1229
1230 if((AGS_LINE_MEMBER_CONNECTED & (line_member->flags)) != 0){
1231 return;
1232 }
1233
1234 line_member->flags |= AGS_LINE_MEMBER_CONNECTED;
1235
1236 ags_line_member_find_port(line_member);
1237
1238 control = gtk_bin_get_child(GTK_BIN(line_member));
1239
1240 if((AGS_LINE_MEMBER_APPLY_INITIAL & (line_member->flags)) != 0){
1241 GtkAdjustment *adjustment;
1242
1243 gboolean is_toggled;
1244
1245 adjustment = NULL;
1246 is_toggled = FALSE;
1247
1248 if(AGS_IS_DIAL(control)){
1249 adjustment = AGS_DIAL(control)->adjustment;
1250 }else if(GTK_IS_RANGE(control)){
1251 adjustment = gtk_range_get_adjustment(GTK_RANGE(control));
1252 }else if(GTK_IS_SPIN_BUTTON(control)){
1253 adjustment = gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(control));
1254 }else if(GTK_IS_TOGGLE_BUTTON(control)){
1255 line_member->active = gtk_toggle_button_get_active((GtkToggleButton *) control);
1256
1257 is_toggled = TRUE;
1258 }
1259
1260 if(is_toggled){
1261 ags_line_member_change_port(line_member,
1262 &(line_member->active));
1263 }else if(adjustment != NULL){
1264 gdouble value;
1265
1266 value = gtk_adjustment_get_value(adjustment);
1267
1268 ags_line_member_change_port(line_member,
1269 &value);
1270 }
1271
1272 line_member->flags &= (~AGS_LINE_MEMBER_APPLY_INITIAL);
1273 }
1274
1275 /* widget callback */
1276 if(line_member->widget_type == AGS_TYPE_DIAL){
1277 g_signal_connect_after(GTK_WIDGET(control), "value-changed",
1278 G_CALLBACK(ags_line_member_dial_changed_callback), line_member);
1279 }else if(g_type_is_a(line_member->widget_type, GTK_TYPE_SCALE)){
1280 g_signal_connect_after(GTK_WIDGET(control), "value-changed",
1281 G_CALLBACK(ags_line_member_scale_changed_callback), line_member);
1282 }else if(line_member->widget_type == GTK_TYPE_SPIN_BUTTON){
1283 g_signal_connect_after(GTK_WIDGET(control), "value-changed",
1284 G_CALLBACK(ags_line_member_spin_button_changed_callback), line_member);
1285 }else if(line_member->widget_type == GTK_TYPE_CHECK_BUTTON){
1286 g_signal_connect_after(GTK_WIDGET(control), "clicked",
1287 G_CALLBACK(ags_line_member_check_button_clicked_callback), line_member);
1288 }else if(line_member->widget_type == GTK_TYPE_TOGGLE_BUTTON){
1289 g_signal_connect_after(GTK_WIDGET(control), "clicked",
1290 G_CALLBACK(ags_line_member_toggle_button_clicked_callback), line_member);
1291 }else if(line_member->widget_type == GTK_TYPE_BUTTON){
1292 g_signal_connect_after(GTK_WIDGET(control), "clicked",
1293 G_CALLBACK(ags_line_member_button_clicked_callback), line_member);
1294 }
1295 }
1296
1297 void
ags_line_member_disconnect(AgsConnectable * connectable)1298 ags_line_member_disconnect(AgsConnectable *connectable)
1299 {
1300 AgsLineMember *line_member;
1301 GtkWidget *control;
1302
1303 line_member = AGS_LINE_MEMBER(connectable);
1304
1305 if((AGS_LINE_MEMBER_CONNECTED & (line_member->flags)) == 0){
1306 return;
1307 }
1308
1309 line_member->flags &= (~AGS_LINE_MEMBER_CONNECTED);
1310
1311 /* widget callback */
1312 control = gtk_bin_get_child(GTK_BIN(line_member));
1313
1314 if(line_member->widget_type == AGS_TYPE_DIAL){
1315 g_object_disconnect(GTK_WIDGET(control),
1316 "any_signal::value-changed",
1317 G_CALLBACK(ags_line_member_dial_changed_callback),
1318 line_member,
1319 NULL);
1320 }else if(g_type_is_a(line_member->widget_type, GTK_TYPE_SCALE)){
1321 g_object_disconnect(GTK_WIDGET(control),
1322 "any_signal::value-changed",
1323 G_CALLBACK(ags_line_member_scale_changed_callback),
1324 line_member,
1325 NULL);
1326 }else if(line_member->widget_type == GTK_TYPE_SPIN_BUTTON){
1327 g_object_disconnect(GTK_WIDGET(control),
1328 "any_signal::value-changed",
1329 G_CALLBACK(ags_line_member_spin_button_changed_callback),
1330 line_member,
1331 NULL);
1332 }else if(line_member->widget_type == GTK_TYPE_CHECK_BUTTON){
1333 g_object_disconnect(GTK_WIDGET(control),
1334 "any_signal::clicked",
1335 G_CALLBACK(ags_line_member_check_button_clicked_callback),
1336 line_member,
1337 NULL);
1338 }else if(line_member->widget_type == GTK_TYPE_TOGGLE_BUTTON){
1339 g_object_disconnect(GTK_WIDGET(control),
1340 "any_signal::clicked",
1341 G_CALLBACK(ags_line_member_toggle_button_clicked_callback),
1342 line_member,
1343 NULL);
1344 }else if(line_member->widget_type == GTK_TYPE_BUTTON){
1345 g_object_disconnect(GTK_WIDGET(control),
1346 "any_signal::clicked",
1347 G_CALLBACK(ags_line_member_button_clicked_callback),
1348 line_member,
1349 NULL);
1350 }
1351 }
1352
1353 GtkWidget*
ags_line_member_get_widget(AgsLineMember * line_member)1354 ags_line_member_get_widget(AgsLineMember *line_member)
1355 {
1356 return(gtk_bin_get_child(GTK_BIN(line_member)));
1357 }
1358
1359 /**
1360 * ags_line_member_set_label:
1361 * @line_member: an #AgsLineMember
1362 * @label: the label of the control
1363 *
1364 * Modify the label of the line member.
1365 */
1366 void
ags_line_member_set_label(AgsLineMember * line_member,gchar * label)1367 ags_line_member_set_label(AgsLineMember *line_member,
1368 gchar *label)
1369 {
1370 GtkWidget *child_widget;
1371
1372 if(g_type_is_a(line_member->widget_type,
1373 GTK_TYPE_BUTTON)){
1374 child_widget = gtk_bin_get_child(GTK_BIN(line_member));
1375
1376 g_object_set(G_OBJECT(child_widget),
1377 "label", label,
1378 NULL);
1379 }else{
1380 gtk_frame_set_label_widget((GtkFrame *) line_member,
1381 g_object_new(GTK_TYPE_LABEL,
1382 "wrap", FALSE,
1383 "use-markup", TRUE,
1384 "label", g_markup_printf_escaped("<small>%s</small>", label),
1385 NULL));
1386 }
1387
1388
1389 line_member->widget_label = label;
1390 }
1391
1392 void
ags_line_member_real_change_port(AgsLineMember * line_member,gpointer port_data)1393 ags_line_member_real_change_port(AgsLineMember *line_member,
1394 gpointer port_data)
1395 {
1396 if((AGS_LINE_MEMBER_RESET_BY_ATOMIC & (line_member->flags)) != 0){
1397 AgsPort *port;
1398
1399 GRecMutex *port_mutex;
1400
1401 GValue value = {0,};
1402
1403 port = line_member->port;
1404
1405 if(port == NULL){
1406 g_warning("ags_line_member_change_port() - no port available");
1407 return;
1408 }
1409
1410 /* get port mutex */
1411 port_mutex = AGS_PORT_GET_OBJ_MUTEX(port);
1412
1413 /* change */
1414 g_rec_mutex_lock(port_mutex);
1415
1416 if(!port->port_value_is_pointer){
1417 if(port->port_value_type == G_TYPE_BOOLEAN){
1418 g_value_init(&value,
1419 G_TYPE_BOOLEAN);
1420
1421 g_value_set_boolean(&value,
1422 ((gboolean *) port_data)[0]);
1423 }else if(port->port_value_type == G_TYPE_INT64){
1424 g_value_init(&value,
1425 G_TYPE_INT64);
1426 g_value_set_int64(&value,
1427 ((gint *) port_data)[0]);
1428 }else if(port->port_value_type == G_TYPE_UINT64){
1429 g_value_init(&value,
1430 G_TYPE_UINT64);
1431
1432 g_value_set_uint64(&value,
1433 ((guint *) port_data)[0]);
1434 }else if(port->port_value_type == G_TYPE_FLOAT){
1435 gdouble val;
1436 gfloat port_val;
1437
1438 if(GTK_IS_TOGGLE_BUTTON(gtk_bin_get_child((GtkBin *) line_member))){
1439 if(((gboolean *) port_data)[0]){
1440 val = 1.0;
1441 }else{
1442 val = 0.0;
1443 }
1444 }else{
1445 val = ((gdouble *) port_data)[0];
1446 }
1447
1448 port_val = (gfloat) val;
1449
1450 if(line_member->conversion != NULL){
1451 gboolean success;
1452
1453 success = FALSE;
1454
1455 if(AGS_IS_DIAL(gtk_bin_get_child((GtkBin *) line_member))){
1456 success = TRUE;
1457 }else if(GTK_IS_RANGE(gtk_bin_get_child((GtkBin *) line_member))){
1458 success = TRUE;
1459 }else if(GTK_IS_SPIN_BUTTON(gtk_bin_get_child((GtkBin *) line_member))){
1460 success = TRUE;
1461 }else{
1462 g_warning("unsupported child type in conversion");
1463 }
1464
1465 if(success){
1466 port_val = ags_conversion_convert(line_member->conversion,
1467 val,
1468 FALSE);
1469 }
1470 }
1471
1472 g_value_init(&value,
1473 G_TYPE_FLOAT);
1474
1475 g_value_set_float(&value,
1476 (gfloat) port_val);
1477 }else if(port->port_value_type == G_TYPE_DOUBLE){
1478 gdouble val;
1479 gdouble port_val;
1480
1481 if(GTK_IS_TOGGLE_BUTTON(gtk_bin_get_child((GtkBin *) line_member))){
1482 if(((gboolean *) port_data)[0]){
1483 val = 1.0;
1484 }else{
1485 val = 0.0;
1486 }
1487 }else{
1488 val = ((gdouble *) port_data)[0];
1489 }
1490
1491 port_val = val;
1492
1493 if(line_member->conversion != NULL){
1494 gboolean success;
1495
1496 success = FALSE;
1497
1498 if(AGS_IS_DIAL(gtk_bin_get_child((GtkBin *) line_member))){
1499 success = TRUE;
1500 }else if(GTK_IS_RANGE(gtk_bin_get_child((GtkBin *) line_member))){
1501 success = TRUE;
1502 }else if(GTK_IS_SPIN_BUTTON(gtk_bin_get_child((GtkBin *) line_member))){
1503 success = TRUE;
1504 }else{
1505 g_warning("unsupported child type in conversion");
1506 }
1507
1508 if(success){
1509 port_val = ags_conversion_convert(line_member->conversion,
1510 val,
1511 FALSE);
1512 }
1513 }
1514
1515 g_value_init(&value,
1516 G_TYPE_DOUBLE);
1517
1518 g_value_set_double(&value,
1519 port_val);
1520 }
1521 }else{
1522 if(port->port_value_type == G_TYPE_OBJECT){
1523 g_value_init(&value,
1524 G_TYPE_OBJECT);
1525 g_value_set_object(&value,
1526 port_data);
1527 }else{
1528 if(port->port_value_type == G_TYPE_BOOLEAN ||
1529 port->port_value_type == G_TYPE_INT64 ||
1530 port->port_value_type == G_TYPE_UINT64 ||
1531 port->port_value_type == G_TYPE_FLOAT ||
1532 port->port_value_type == G_TYPE_DOUBLE ||
1533 port->port_value_type == G_TYPE_POINTER){
1534 g_value_init(&value,
1535 G_TYPE_POINTER);
1536
1537 g_value_set_pointer(&value,
1538 port_data);
1539
1540 }
1541 }
1542 }
1543
1544 g_rec_mutex_unlock(port_mutex);
1545
1546 ags_port_safe_write(line_member->port,
1547 &value);
1548
1549 if((AGS_LINE_MEMBER_APPLY_RECALL & (line_member->flags)) != 0){
1550 ags_port_safe_write(line_member->recall_port,
1551 &value);
1552 }
1553 }
1554
1555 if((AGS_LINE_MEMBER_RESET_BY_TASK & (line_member->flags)) != 0){
1556 AgsTask *task;
1557
1558 AgsApplicationContext *application_context;
1559
1560 application_context = ags_application_context_get_instance();
1561
1562 task = (AgsTask *) g_object_new(line_member->task_type,
1563 line_member->control_port, port_data,
1564 NULL);
1565
1566 ags_ui_provider_schedule_task(AGS_UI_PROVIDER(application_context),
1567 (AgsTask *) task);
1568 }
1569 }
1570
1571 /**
1572 * ags_line_change_port:
1573 * @line_member: an #AgsLineMember
1574 * @port_data: the port's value
1575 *
1576 * Is emitted as port's value is modified.
1577 *
1578 * Since: 3.0.0
1579 */
1580 void
ags_line_member_change_port(AgsLineMember * line_member,gpointer port_data)1581 ags_line_member_change_port(AgsLineMember *line_member,
1582 gpointer port_data)
1583 {
1584 g_return_if_fail(AGS_IS_LINE_MEMBER(line_member));
1585
1586 g_object_ref((GObject *) line_member);
1587 g_signal_emit(G_OBJECT(line_member),
1588 line_member_signals[CHANGE_PORT], 0,
1589 port_data);
1590 g_object_unref((GObject *) line_member);
1591 }
1592
1593 AgsPort*
ags_line_member_find_specifier(GList * recall,gchar * specifier)1594 ags_line_member_find_specifier(GList *recall,
1595 gchar *specifier)
1596 {
1597 AgsPort *current_port;
1598
1599 GList *start_port, *port;
1600
1601 current_port = NULL;
1602
1603 while(recall != NULL){
1604 if(ags_recall_test_behaviour_flags(recall->data, AGS_SOUND_BEHAVIOUR_BULK_MODE)){
1605 recall = recall->next;
1606
1607 continue;
1608 }
1609
1610 g_object_get(recall->data,
1611 "port", &start_port,
1612 NULL);
1613
1614 port = ags_port_find_specifier(start_port,
1615 specifier);
1616
1617 #ifdef AGS_DEBUG
1618 g_message("search port in %s", G_OBJECT_TYPE_NAME(recall->data));
1619 #endif
1620
1621 if(port != NULL){
1622 current_port = port->data;
1623 }
1624
1625 g_list_free_full(start_port,
1626 g_object_unref);
1627
1628 if(current_port != NULL){
1629 break;
1630 }
1631
1632 /* iterate */
1633 recall = recall->next;
1634 }
1635
1636 return(current_port);
1637 }
1638
1639 GList*
ags_line_member_real_find_port(AgsLineMember * line_member)1640 ags_line_member_real_find_port(AgsLineMember *line_member)
1641 {
1642 AgsMachine *machine;
1643 GtkWidget *parent;
1644
1645 AgsAudio *audio;
1646 AgsChannel *channel;
1647 AgsPort *audio_port, *channel_port;
1648 AgsPort *recall_audio_port, *recall_channel_port;
1649
1650 GList *port;
1651 GList *start_list;
1652
1653 gchar *specifier;
1654
1655 if(!AGS_IS_LINE_MEMBER(line_member)){
1656 return(NULL);
1657 }
1658
1659 specifier = line_member->specifier;
1660
1661 if(specifier == NULL){
1662 return(NULL);
1663 }
1664
1665 machine = (AgsMachine *) gtk_widget_get_ancestor(GTK_WIDGET(line_member),
1666 AGS_TYPE_MACHINE);
1667 parent = gtk_widget_get_ancestor(GTK_WIDGET(line_member),
1668 AGS_TYPE_LINE);
1669
1670 audio = machine->audio;
1671
1672 if(parent != NULL){
1673 channel = AGS_LINE(parent)->channel;
1674 }else{
1675 parent = gtk_widget_get_ancestor(GTK_WIDGET(line_member),
1676 AGS_TYPE_EFFECT_LINE);
1677
1678 if(parent != NULL){
1679 channel = AGS_EFFECT_LINE(parent)->channel;
1680 }else{
1681 return(NULL);
1682 }
1683 }
1684
1685 audio_port = NULL;
1686 channel_port = NULL;
1687
1688 recall_audio_port = NULL;
1689 recall_channel_port = NULL;
1690
1691 port = NULL;
1692
1693 /* play context */
1694 g_object_get(channel,
1695 "play", &start_list,
1696 NULL);
1697
1698 channel_port = ags_line_member_find_specifier(start_list,
1699 specifier);
1700
1701 g_list_free_full(start_list,
1702 g_object_unref);
1703
1704 /* recall context */
1705 g_object_get(channel,
1706 "recall", &start_list,
1707 NULL);
1708
1709 recall_channel_port = ags_line_member_find_specifier(start_list,
1710 specifier);
1711
1712 g_list_free_full(start_list,
1713 g_object_unref);
1714
1715 if(channel_port != NULL){
1716 port = g_list_prepend(port,
1717 channel_port);
1718 }
1719
1720 if(recall_channel_port != NULL){
1721 port = g_list_prepend(port,
1722 recall_channel_port);
1723 }
1724
1725 /* search audio */
1726 if(channel_port == NULL &&
1727 recall_channel_port == NULL){
1728 GList *start_list;
1729
1730 /* play context */
1731 g_object_get(audio,
1732 "play", &start_list,
1733 NULL);
1734
1735 audio_port = ags_line_member_find_specifier(start_list,
1736 specifier);
1737
1738 g_list_free_full(start_list,
1739 g_object_unref);
1740
1741 /* recall context */
1742 g_object_get(audio,
1743 "recall", &start_list,
1744 NULL);
1745
1746 recall_audio_port = ags_line_member_find_specifier(start_list,
1747 specifier);
1748
1749 g_list_free_full(start_list,
1750 g_object_unref);
1751
1752 if(audio_port != NULL){
1753 port = g_list_prepend(port,
1754 audio_port);
1755 }
1756
1757 if(recall_audio_port != NULL){
1758 port = g_list_prepend(port,
1759 recall_audio_port);
1760 }
1761 }
1762
1763 if(channel_port != NULL || recall_channel_port != NULL){
1764 g_object_set(G_OBJECT(line_member),
1765 "port", channel_port,
1766 NULL);
1767
1768 g_object_set(G_OBJECT(line_member),
1769 "recall-port", recall_channel_port,
1770 NULL);
1771 }else if(audio_port != NULL || recall_audio_port != NULL){
1772 g_object_set(G_OBJECT(line_member),
1773 "port", audio_port,
1774 NULL);
1775
1776 g_object_set(G_OBJECT(line_member),
1777 "recall-port", recall_audio_port,
1778 NULL);
1779 }
1780
1781 return(port);
1782 }
1783
1784 /**
1785 * ags_line_member_find_port:
1786 * @line_member: an #AgsLineMember
1787 *
1788 * Lookup ports of assigned recalls.
1789 *
1790 * Returns: a #GList-struct containing all related #AgsPort
1791 *
1792 * Since: 3.0.0
1793 */
1794 GList*
ags_line_member_find_port(AgsLineMember * line_member)1795 ags_line_member_find_port(AgsLineMember *line_member)
1796 {
1797 GList *list;
1798
1799 list = NULL;
1800 g_return_val_if_fail(AGS_IS_LINE_MEMBER(line_member),
1801 NULL);
1802
1803 g_object_ref((GObject *) line_member);
1804 g_signal_emit((GObject *) line_member,
1805 line_member_signals[FIND_PORT], 0,
1806 &list);
1807 g_object_unref((GObject *) line_member);
1808
1809 return(list);
1810 }
1811
1812 /**
1813 * ags_line_member_chained_event:
1814 * @line_member: an #AgsLineMember
1815 *
1816 * Chain changed control and apply the very same value to grouped
1817 * controls if sticky controls set.
1818 *
1819 * Since: 3.0.0
1820 */
1821 void
ags_line_member_chained_event(AgsLineMember * line_member)1822 ags_line_member_chained_event(AgsLineMember *line_member)
1823 {
1824 AgsMachine *machine;
1825
1826 if(!AGS_IS_LINE_MEMBER(line_member) ||
1827 (AGS_LINE_MEMBER_BLOCK_CHAINED & (line_member->flags)) != 0){
1828 return;
1829 }
1830
1831 machine = (AgsMachine *) gtk_widget_get_ancestor(GTK_WIDGET(line_member),
1832 AGS_TYPE_MACHINE);
1833
1834 if((AGS_MACHINE_STICKY_CONTROLS & (machine->flags)) != 0){
1835 AgsPad *pad;
1836 AgsEffectPad *effect_pad;
1837 GtkWidget *child_widget;
1838
1839 GtkAdjustment *adjustment;
1840
1841 gboolean is_active;
1842
1843 pad = (AgsPad *) gtk_widget_get_ancestor(GTK_WIDGET(line_member),
1844 AGS_TYPE_PAD);
1845
1846 effect_pad = (AgsEffectPad *) gtk_widget_get_ancestor(GTK_WIDGET(line_member),
1847 AGS_TYPE_EFFECT_PAD);
1848
1849 is_active = FALSE;
1850
1851 child_widget = gtk_bin_get_child((GtkBin *) line_member);
1852
1853 if(AGS_IS_DIAL(child_widget) ||
1854 GTK_IS_SPIN_BUTTON(child_widget) ||
1855 GTK_IS_SCALE(child_widget)){
1856 g_object_get(gtk_bin_get_child((GtkBin *) line_member),
1857 "adjustment", &adjustment,
1858 NULL);
1859 }else if(GTK_IS_TOGGLE_BUTTON(child_widget)){
1860 is_active = gtk_toggle_button_get_active((GtkToggleButton *) gtk_bin_get_child(GTK_BIN(line_member)));
1861 }
1862
1863 if(pad != NULL){
1864 AgsLine *line;
1865
1866 GList *list_line, *list_line_start;
1867 GList *list_line_member, *list_line_member_start;
1868
1869 line = (AgsLine *) gtk_widget_get_ancestor(GTK_WIDGET(line_member),
1870 AGS_TYPE_LINE);
1871
1872 list_line =
1873 list_line_start = gtk_container_get_children(GTK_CONTAINER(pad->expander_set));
1874
1875 while((list_line = ags_line_find_next_grouped(list_line)) != NULL){
1876 if(list_line->data != line){
1877 list_line_member =
1878 list_line_member_start = gtk_container_get_children((GtkContainer *) AGS_LINE(list_line->data)->expander->table);
1879
1880 while(list_line_member != NULL){
1881 if(AGS_IS_LINE_MEMBER(list_line_member->data) &&
1882 !g_strcmp0(line_member->specifier,
1883 AGS_LINE_MEMBER(list_line_member->data)->specifier)){
1884 AGS_LINE_MEMBER(list_line_member->data)->flags |= AGS_LINE_MEMBER_BLOCK_CHAINED;
1885
1886 child_widget = gtk_bin_get_child(GTK_BIN(list_line_member->data));
1887
1888 if(AGS_IS_DIAL(child_widget)){
1889 ags_dial_set_value((AgsDial *) child_widget,
1890 gtk_adjustment_get_value(adjustment));
1891 }else if(GTK_IS_SPIN_BUTTON(child_widget)){
1892 gtk_spin_button_set_value((GtkSpinButton *) child_widget,
1893 gtk_adjustment_get_value(adjustment));
1894 }else if(GTK_IS_SCALE(child_widget)){
1895 gtk_range_set_value((GtkRange *) child_widget,
1896 gtk_adjustment_get_value(adjustment));
1897 }else if(GTK_IS_TOGGLE_BUTTON(child_widget)){
1898 gtk_toggle_button_set_active((GtkToggleButton *) child_widget,
1899 is_active);
1900 }else if(GTK_IS_BUTTON(child_widget)){
1901 gtk_button_clicked((GtkButton *) child_widget);
1902 }
1903
1904 AGS_LINE_MEMBER(list_line_member->data)->flags &= (~AGS_LINE_MEMBER_BLOCK_CHAINED);
1905
1906 break;
1907 }
1908
1909 list_line_member = list_line_member->next;
1910 }
1911
1912 g_list_free(list_line_member_start);
1913 }
1914
1915 list_line = list_line->next;
1916 }
1917
1918 g_list_free(list_line_start);
1919 }else if(effect_pad != NULL){
1920 AgsEffectLine *effect_line;
1921
1922 GList *list_effect_line, *list_effect_line_start;
1923 GList *list_line_member, *list_line_member_start;
1924
1925 effect_line = (AgsEffectLine *) gtk_widget_get_ancestor(GTK_WIDGET(line_member),
1926 AGS_TYPE_EFFECT_LINE);
1927
1928 list_effect_line =
1929 list_effect_line_start = gtk_container_get_children(GTK_CONTAINER(effect_pad->grid));
1930
1931 while((list_effect_line = ags_effect_line_find_next_grouped(list_effect_line)) != NULL){
1932 if(list_effect_line->data != effect_line){
1933 list_line_member =
1934 list_line_member_start = gtk_container_get_children((GtkContainer *) AGS_EFFECT_LINE(list_effect_line->data)->grid);
1935
1936 while(list_line_member != NULL){
1937 if(!g_strcmp0(line_member->specifier,
1938 AGS_LINE_MEMBER(list_line_member->data)->specifier)){
1939 AGS_LINE_MEMBER(list_line_member->data)->flags |= AGS_LINE_MEMBER_BLOCK_CHAINED;
1940
1941 child_widget = gtk_bin_get_child(GTK_BIN(list_line_member->data));
1942
1943 if(AGS_IS_DIAL(child_widget)){
1944 ags_dial_set_value((AgsDial *) child_widget,
1945 gtk_adjustment_get_value(adjustment));
1946 }else if(GTK_IS_SPIN_BUTTON(child_widget)){
1947 gtk_spin_button_set_value((GtkSpinButton *) child_widget,
1948 gtk_adjustment_get_value(adjustment));
1949 }else if(GTK_IS_SCALE(child_widget)){
1950 gtk_range_set_value((GtkRange *) child_widget,
1951 gtk_adjustment_get_value(adjustment));
1952 }else if(GTK_IS_TOGGLE_BUTTON(child_widget)){
1953 gtk_toggle_button_set_active((GtkToggleButton *) child_widget,
1954 is_active);
1955 }else if(GTK_IS_BUTTON(child_widget)){
1956 gtk_button_clicked((GtkButton *) child_widget);
1957 }
1958
1959 AGS_LINE_MEMBER(list_line_member->data)->flags &= (~AGS_LINE_MEMBER_BLOCK_CHAINED);
1960
1961 break;
1962 }
1963
1964 list_line_member = list_line_member->next;
1965 }
1966
1967 g_list_free(list_line_member_start);
1968 }
1969
1970 list_effect_line = list_effect_line->next;
1971 }
1972
1973 g_list_free(list_effect_line_start);
1974 }
1975 }
1976 }
1977
1978 /**
1979 * ags_line_member_new:
1980 *
1981 * Create a new instance of #AgsLineMember
1982 *
1983 * Returns: the new #AgsLineMember
1984 *
1985 * Since: 3.0.0
1986 */
1987 AgsLineMember*
ags_line_member_new()1988 ags_line_member_new()
1989 {
1990 AgsLineMember *line_member;
1991
1992 line_member = (AgsLineMember *) g_object_new(AGS_TYPE_LINE_MEMBER,
1993 NULL);
1994
1995 return(line_member);
1996 }
1997