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_pad.h>
21 #include <ags/X/ags_pad_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
27 #include <ags/i18n.h>
28
29 void ags_pad_class_init(AgsPadClass *pad);
30 void ags_pad_connectable_interface_init(AgsConnectableInterface *connectable);
31 void ags_pad_init(AgsPad *pad);
32 void ags_pad_set_property(GObject *gobject,
33 guint prop_id,
34 const GValue *value,
35 GParamSpec *param_spec);
36 void ags_pad_get_property(GObject *gobject,
37 guint prop_id,
38 GValue *value,
39 GParamSpec *param_spec);
40
41 void ags_pad_connect(AgsConnectable *connectable);
42 void ags_pad_disconnect(AgsConnectable *connectable);
43
44 void ags_pad_real_set_channel(AgsPad *pad, AgsChannel *channel);
45 void ags_pad_real_resize_lines(AgsPad *pad, GType line_type,
46 guint audio_channels, guint audio_channels_old);
47 void ags_pad_real_map_recall(AgsPad *pad,
48 guint output_pad_start);
49 GList* ags_pad_real_find_port(AgsPad *pad);
50
51 /**
52 * SECTION:ags_pad
53 * @short_description: A composite widget to visualize a bunch of #AgsChannel
54 * @title: AgsPad
55 * @section_id:
56 * @include: ags/X/ags_pad.h
57 *
58 * #AgsPad is a composite widget to visualize a bunch of #AgsChannel. It should be
59 * packed by an #AgsMachine.
60 */
61
62 enum{
63 SAMPLERATE_CHANGED,
64 BUFFER_SIZE_CHANGED,
65 FORMAT_CHANGED,
66 SET_CHANNEL,
67 RESIZE_LINES,
68 MAP_RECALL,
69 FIND_PORT,
70 LAST_SIGNAL,
71 };
72
73 enum{
74 PROP_0,
75 PROP_SAMPLERATE,
76 PROP_BUFFER_SIZE,
77 PROP_FORMAT,
78 PROP_CHANNEL,
79 };
80
81 static gpointer ags_pad_parent_class = NULL;
82 static guint pad_signals[LAST_SIGNAL];
83
84 GType
ags_pad_get_type(void)85 ags_pad_get_type(void)
86 {
87 static volatile gsize g_define_type_id__volatile = 0;
88
89 if(g_once_init_enter (&g_define_type_id__volatile)){
90 GType ags_type_pad = 0;
91
92 static const GTypeInfo ags_pad_info = {
93 sizeof(AgsPadClass),
94 NULL, /* base_init */
95 NULL, /* base_finalize */
96 (GClassInitFunc) ags_pad_class_init,
97 NULL, /* class_finalize */
98 NULL, /* class_data */
99 sizeof(AgsPad),
100 0, /* n_preallocs */
101 (GInstanceInitFunc) ags_pad_init,
102 };
103
104 static const GInterfaceInfo ags_connectable_interface_info = {
105 (GInterfaceInitFunc) ags_pad_connectable_interface_init,
106 NULL, /* interface_finalize */
107 NULL, /* interface_data */
108 };
109
110 ags_type_pad = g_type_register_static(GTK_TYPE_BOX,
111 "AgsPad", &ags_pad_info,
112 0);
113
114 g_type_add_interface_static(ags_type_pad,
115 AGS_TYPE_CONNECTABLE,
116 &ags_connectable_interface_info);
117
118 g_once_init_leave(&g_define_type_id__volatile, ags_type_pad);
119 }
120
121 return g_define_type_id__volatile;
122 }
123
124 void
ags_pad_class_init(AgsPadClass * pad)125 ags_pad_class_init(AgsPadClass *pad)
126 {
127 GObjectClass *gobject;
128 GParamSpec *param_spec;
129
130 ags_pad_parent_class = g_type_class_peek_parent(pad);
131
132 /* GObjectClass */
133 gobject = G_OBJECT_CLASS(pad);
134
135 gobject->set_property = ags_pad_set_property;
136 gobject->get_property = ags_pad_get_property;
137
138 //TODO:JK: add finalize
139
140 /* properties */
141 /**
142 * AgsPad:samplerate:
143 *
144 * The samplerate.
145 *
146 * Since: 3.0.0
147 */
148 param_spec = g_param_spec_uint("samplerate",
149 i18n_pspec("samplerate"),
150 i18n_pspec("The samplerate"),
151 0,
152 G_MAXUINT32,
153 AGS_SOUNDCARD_DEFAULT_SAMPLERATE,
154 G_PARAM_READABLE | G_PARAM_WRITABLE);
155 g_object_class_install_property(gobject,
156 PROP_SAMPLERATE,
157 param_spec);
158
159 /**
160 * AgsPad:buffer-size:
161 *
162 * The buffer length.
163 *
164 * Since: 3.0.0
165 */
166 param_spec = g_param_spec_uint("buffer-size",
167 i18n_pspec("buffer size"),
168 i18n_pspec("The buffer size"),
169 0,
170 G_MAXUINT32,
171 AGS_SOUNDCARD_DEFAULT_BUFFER_SIZE,
172 G_PARAM_READABLE | G_PARAM_WRITABLE);
173 g_object_class_install_property(gobject,
174 PROP_BUFFER_SIZE,
175 param_spec);
176
177 /**
178 * AgsPad:format:
179 *
180 * The format.
181 *
182 * Since: 3.0.0
183 */
184 param_spec = g_param_spec_uint("format",
185 i18n_pspec("format"),
186 i18n_pspec("The format"),
187 0,
188 G_MAXUINT32,
189 AGS_SOUNDCARD_DEFAULT_FORMAT,
190 G_PARAM_READABLE | G_PARAM_WRITABLE);
191 g_object_class_install_property(gobject,
192 PROP_FORMAT,
193 param_spec);
194
195 /**
196 * AgsPad:channel:
197 *
198 * The start of a bunch of #AgsChannel to visualize.
199 *
200 * Since: 3.0.0
201 */
202 param_spec = g_param_spec_object("channel",
203 i18n_pspec("assigned channel"),
204 i18n_pspec("The channel it is assigned with"),
205 AGS_TYPE_CHANNEL,
206 G_PARAM_READABLE | G_PARAM_WRITABLE);
207 g_object_class_install_property(gobject,
208 PROP_CHANNEL,
209 param_spec);
210
211 /* AgsPadClass */
212 pad->samplerate_changed = NULL;
213 pad->buffer_size_changed = NULL;
214 pad->format_changed = NULL;
215
216 pad->set_channel = ags_pad_real_set_channel;
217 pad->resize_lines = ags_pad_real_resize_lines;
218 pad->map_recall = ags_pad_real_map_recall;
219 pad->find_port = ags_pad_real_find_port;
220
221 /* signals */
222 /**
223 * AgsPad::samplerate-changed:
224 * @pad: the #AgsPad
225 * @samplerate: the samplerate
226 * @old_samplerate: the old samplerate
227 *
228 * The ::samplerate-changed signal notifies about changed samplerate.
229 *
230 * Since: 3.0.0
231 */
232 pad_signals[SAMPLERATE_CHANGED] =
233 g_signal_new("samplerate-changed",
234 G_TYPE_FROM_CLASS(pad),
235 G_SIGNAL_RUN_LAST,
236 G_STRUCT_OFFSET(AgsPadClass, samplerate_changed),
237 NULL, NULL,
238 ags_cclosure_marshal_VOID__UINT_UINT,
239 G_TYPE_NONE, 2,
240 G_TYPE_UINT,
241 G_TYPE_UINT);
242
243 /**
244 * AgsPad::buffer-size-changed:
245 * @pad: the #AgsPad
246 * @buffer_size: the buffer size
247 * @old_buffer_size: the old buffer size
248 *
249 * The ::buffer-size-changed signal notifies about changed buffer size.
250 *
251 * Since: 3.0.0
252 */
253 pad_signals[BUFFER_SIZE_CHANGED] =
254 g_signal_new("buffer-size-changed",
255 G_TYPE_FROM_CLASS(pad),
256 G_SIGNAL_RUN_LAST,
257 G_STRUCT_OFFSET(AgsPadClass, buffer_size_changed),
258 NULL, NULL,
259 ags_cclosure_marshal_VOID__UINT_UINT,
260 G_TYPE_NONE, 2,
261 G_TYPE_UINT,
262 G_TYPE_UINT);
263
264 /**
265 * AgsPad::format-changed:
266 * @pad: the #AgsPad
267 * @format: the format
268 * @old_format: the old format
269 *
270 * The ::format-changed signal notifies about changed format.
271 *
272 * Since: 3.0.0
273 */
274 pad_signals[FORMAT_CHANGED] =
275 g_signal_new("format-changed",
276 G_TYPE_FROM_CLASS(pad),
277 G_SIGNAL_RUN_LAST,
278 G_STRUCT_OFFSET(AgsPadClass, format_changed),
279 NULL, NULL,
280 ags_cclosure_marshal_VOID__UINT_UINT,
281 G_TYPE_NONE, 2,
282 G_TYPE_UINT,
283 G_TYPE_UINT);
284
285 /**
286 * AgsPad::set-channel:
287 * @pad: the #AgsPad to modify
288 * @channel: the #AgsChannel to set
289 *
290 * The ::set-channel signal notifies about changed channel.
291 *
292 * Since: 3.0.0
293 */
294 pad_signals[SET_CHANNEL] =
295 g_signal_new("set-channel",
296 G_TYPE_FROM_CLASS(pad),
297 G_SIGNAL_RUN_LAST,
298 G_STRUCT_OFFSET(AgsPadClass, set_channel),
299 NULL, NULL,
300 g_cclosure_marshal_VOID__OBJECT,
301 G_TYPE_NONE, 1,
302 G_TYPE_OBJECT);
303
304 /**
305 * AgsPad::resize-lines:
306 * @pad: the #AgsPad to resize
307 * @line_type: the channel type
308 * @audio_channels: count of lines
309 * @audio_channels_old: old count of lines
310 *
311 * The ::resize-lines is emitted as count of lines pack is modified.
312 *
313 * Since: 3.0.0
314 */
315 pad_signals[RESIZE_LINES] =
316 g_signal_new("resize-lines",
317 G_TYPE_FROM_CLASS(pad),
318 G_SIGNAL_RUN_LAST,
319 G_STRUCT_OFFSET(AgsPadClass, resize_lines),
320 NULL, NULL,
321 ags_cclosure_marshal_VOID__ULONG_UINT_UINT,
322 G_TYPE_NONE, 3,
323 G_TYPE_ULONG, G_TYPE_UINT, G_TYPE_UINT);
324
325
326 /**
327 * AgsPad::map-recall:
328 * @pad: the #AgsPad to resize
329 * @output_pad_start: start of output pad
330 *
331 * The ::map-recall as recall should be mapped
332 *
333 * Since: 3.0.0
334 */
335 pad_signals[MAP_RECALL] =
336 g_signal_new("map-recall",
337 G_TYPE_FROM_CLASS(pad),
338 G_SIGNAL_RUN_LAST,
339 G_STRUCT_OFFSET(AgsPadClass, map_recall),
340 NULL, NULL,
341 g_cclosure_marshal_VOID__UINT,
342 G_TYPE_NONE, 1,
343 G_TYPE_UINT);
344
345 /**
346 * AgsPad::find-port:
347 * @pad: the #AgsPad to resize
348 *
349 * The ::find-port retrieves all associated ports
350 *
351 * Returns: a #GList-struct with associated ports
352 *
353 * Since: 3.0.0
354 */
355 pad_signals[FIND_PORT] =
356 g_signal_new("find-port",
357 G_TYPE_FROM_CLASS(pad),
358 G_SIGNAL_RUN_LAST,
359 G_STRUCT_OFFSET(AgsPadClass, find_port),
360 NULL, NULL,
361 ags_cclosure_marshal_POINTER__VOID,
362 G_TYPE_POINTER, 0);
363 }
364
365 void
ags_pad_connectable_interface_init(AgsConnectableInterface * connectable)366 ags_pad_connectable_interface_init(AgsConnectableInterface *connectable)
367 {
368 connectable->is_ready = NULL;
369 connectable->is_connected = NULL;
370 connectable->connect = ags_pad_connect;
371 connectable->disconnect = ags_pad_disconnect;
372 }
373
374 void
ags_pad_init(AgsPad * pad)375 ags_pad_init(AgsPad *pad)
376 {
377 GtkBox *hbox;
378
379 AgsConfig *config;
380
381 gtk_orientable_set_orientation(GTK_ORIENTABLE(pad),
382 GTK_ORIENTATION_VERTICAL);
383
384 pad->flags = 0;
385
386 pad->name = NULL;
387
388 pad->version = AGS_VERSION;
389 pad->build_id = AGS_BUILD_ID;
390
391 config = ags_config_get_instance();
392
393 pad->samplerate = ags_soundcard_helper_config_get_samplerate(config);
394 pad->buffer_size = ags_soundcard_helper_config_get_buffer_size(config);
395 pad->format = ags_soundcard_helper_config_get_format(config);
396
397 pad->channel = NULL;
398
399 pad->cols = 2;
400
401 pad->expander_set = ags_expander_set_new(1, 1);
402 gtk_box_pack_start((GtkBox *) pad, (GtkWidget *) pad->expander_set, TRUE, TRUE, 0);
403
404 hbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,
405 0);
406 gtk_box_pack_start((GtkBox *) pad, (GtkWidget *) hbox, FALSE, FALSE, 0);
407
408 pad->group = (GtkToggleButton *) gtk_toggle_button_new_with_label("G");
409 gtk_toggle_button_set_active(pad->group, TRUE);
410 gtk_box_pack_start((GtkBox *) hbox, (GtkWidget *) pad->group, FALSE, FALSE, 0);
411
412 pad->mute = (GtkToggleButton *) gtk_toggle_button_new_with_label("M");
413 gtk_box_pack_start((GtkBox *) hbox, (GtkWidget *) pad->mute, FALSE, FALSE, 0);
414
415 pad->solo = (GtkToggleButton *) gtk_toggle_button_new_with_label("S");
416 gtk_box_pack_start((GtkBox *) hbox, (GtkWidget *) pad->solo, FALSE, FALSE, 0);
417
418 pad->play = NULL;
419 }
420
421 void
ags_pad_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)422 ags_pad_set_property(GObject *gobject,
423 guint prop_id,
424 const GValue *value,
425 GParamSpec *param_spec)
426 {
427 AgsPad *pad;
428
429 pad = AGS_PAD(gobject);
430
431 switch(prop_id){
432 case PROP_SAMPLERATE:
433 {
434 GList *start_list, *list;
435
436 guint samplerate, old_samplerate;
437
438 samplerate = g_value_get_uint(value);
439 old_samplerate = pad->samplerate;
440
441 if(samplerate == old_samplerate){
442 return;
443 }
444
445 pad->samplerate = samplerate;
446
447 ags_pad_samplerate_changed(pad,
448 samplerate, old_samplerate);
449
450 list =
451 start_list = gtk_container_get_children((GtkContainer *) pad->expander_set);
452
453 while(list != NULL){
454 if(AGS_LINE(list->data)){
455 g_object_set(list->data,
456 "samplerate", samplerate,
457 NULL);
458 }
459
460 list = list->next;
461 }
462
463 g_list_free(start_list);
464 }
465 break;
466 case PROP_BUFFER_SIZE:
467 {
468 GList *start_list, *list;
469
470 guint buffer_size, old_buffer_size;
471
472 buffer_size = g_value_get_uint(value);
473 old_buffer_size = pad->buffer_size;
474
475 if(buffer_size == old_buffer_size){
476 return;
477 }
478
479 pad->buffer_size = buffer_size;
480
481 ags_pad_buffer_size_changed(pad,
482 buffer_size, old_buffer_size);
483
484 list =
485 start_list = gtk_container_get_children((GtkContainer *) pad->expander_set);
486
487 while(list != NULL){
488 if(AGS_LINE(list->data)){
489 g_object_set(list->data,
490 "buffer-size", buffer_size,
491 NULL);
492 }
493
494 list = list->next;
495 }
496
497 g_list_free(start_list);
498 }
499 break;
500 case PROP_FORMAT:
501 {
502 GList *start_list, *list;
503
504 guint format, old_format;
505
506 format = g_value_get_uint(value);
507 old_format = pad->format;
508
509 if(format == old_format){
510 return;
511 }
512
513 pad->format = format;
514
515 ags_pad_format_changed(pad,
516 format, old_format);
517
518 list =
519 start_list = gtk_container_get_children((GtkContainer *) pad->expander_set);
520
521 while(list != NULL){
522 if(AGS_LINE(list->data)){
523 g_object_set(list->data,
524 "format", format,
525 NULL);
526 }
527
528 list = list->next;
529 }
530
531 g_list_free(start_list);
532 }
533 break;
534 case PROP_CHANNEL:
535 {
536 AgsChannel *channel;
537
538 channel = (AgsChannel *) g_value_get_object(value);
539
540 ags_pad_set_channel(pad, channel);
541 }
542 break;
543 default:
544 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
545 break;
546 }
547 }
548
549 void
ags_pad_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)550 ags_pad_get_property(GObject *gobject,
551 guint prop_id,
552 GValue *value,
553 GParamSpec *param_spec)
554 {
555 AgsPad *pad;
556
557 pad = AGS_PAD(gobject);
558
559 switch(prop_id){
560 case PROP_SAMPLERATE:
561 {
562 g_value_set_uint(value,
563 pad->samplerate);
564 }
565 break;
566 case PROP_BUFFER_SIZE:
567 {
568 g_value_set_uint(value,
569 pad->buffer_size);
570 }
571 break;
572 case PROP_FORMAT:
573 {
574 g_value_set_uint(value,
575 pad->format);
576 }
577 break;
578 case PROP_CHANNEL:
579 {
580 g_value_set_object(value, pad->channel);
581 }
582 break;
583 default:
584 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
585 break;
586 }
587 }
588
589 void
ags_pad_connect(AgsConnectable * connectable)590 ags_pad_connect(AgsConnectable *connectable)
591 {
592 AgsPad *pad;
593 GList *line_list, *line_list_start;
594
595 /* AgsPad */
596 pad = AGS_PAD(connectable);
597
598 if((AGS_PAD_CONNECTED & (pad->flags)) != 0){
599 return;
600 }
601
602 pad->flags |= AGS_PAD_CONNECTED;
603
604 if((AGS_PAD_PREMAPPED_RECALL & (pad->flags)) == 0){
605 if((AGS_PAD_MAPPED_RECALL & (pad->flags)) == 0){
606 ags_pad_map_recall(pad,
607 0);
608 }
609 }else{
610 pad->flags &= (~AGS_PAD_PREMAPPED_RECALL);
611
612 ags_pad_find_port(pad);
613 }
614
615 /* GtkButton */
616 g_signal_connect_after((GObject *) pad->group, "clicked",
617 G_CALLBACK(ags_pad_group_clicked_callback), (gpointer) pad);
618
619 g_signal_connect_after((GObject *) pad->mute, "clicked",
620 G_CALLBACK(ags_pad_mute_clicked_callback), (gpointer) pad);
621
622 g_signal_connect_after((GObject *) pad->solo, "clicked",
623 G_CALLBACK(ags_pad_solo_clicked_callback), (gpointer) pad);
624
625 /* AgsLine */
626 line_list_start =
627 line_list = gtk_container_get_children(GTK_CONTAINER(pad->expander_set));
628
629 while(line_list != NULL){
630 ags_connectable_connect(AGS_CONNECTABLE(line_list->data));
631
632 line_list = line_list->next;
633 }
634
635 g_list_free(line_list_start);
636 }
637
638 void
ags_pad_disconnect(AgsConnectable * connectable)639 ags_pad_disconnect(AgsConnectable *connectable)
640 {
641 AgsPad *pad;
642 GList *line_list, *line_list_start;
643
644 /* AgsPad */
645 pad = AGS_PAD(connectable);
646
647 if((AGS_PAD_CONNECTED & (pad->flags)) == 0){
648 return;
649 }
650
651 pad->flags &= (~AGS_PAD_CONNECTED);
652
653 /* AgsLine */
654 line_list_start =
655 line_list = gtk_container_get_children(GTK_CONTAINER(pad->expander_set));
656
657 while(line_list != NULL){
658 ags_connectable_disconnect(AGS_CONNECTABLE(line_list->data));
659
660 line_list = line_list->next;
661 }
662
663 g_list_free(line_list_start);
664
665 g_signal_handlers_disconnect_by_data(pad->channel,
666 pad);
667 }
668
669 /**
670 * ags_pad_samplerate_changed:
671 * @pad: the #AgsPad
672 * @samplerate: the samplerate
673 * @old_samplerate: the old samplerate
674 *
675 * Notify about samplerate changed.
676 *
677 * Since: 3.0.0
678 */
679 void
ags_pad_samplerate_changed(AgsPad * pad,guint samplerate,guint old_samplerate)680 ags_pad_samplerate_changed(AgsPad *pad,
681 guint samplerate, guint old_samplerate)
682 {
683 g_return_if_fail(AGS_IS_PAD(pad));
684
685 g_object_ref((GObject *) pad);
686 g_signal_emit(G_OBJECT(pad),
687 pad_signals[SAMPLERATE_CHANGED], 0,
688 samplerate,
689 old_samplerate);
690 g_object_unref((GObject *) pad);
691 }
692
693 /**
694 * ags_pad_buffer_size_changed:
695 * @pad: the #AgsPad
696 * @buffer_size: the buffer_size
697 * @old_buffer_size: the old buffer_size
698 *
699 * Notify about buffer_size changed.
700 *
701 * Since: 3.0.0
702 */
703 void
ags_pad_buffer_size_changed(AgsPad * pad,guint buffer_size,guint old_buffer_size)704 ags_pad_buffer_size_changed(AgsPad *pad,
705 guint buffer_size, guint old_buffer_size)
706 {
707 g_return_if_fail(AGS_IS_PAD(pad));
708
709 g_object_ref((GObject *) pad);
710 g_signal_emit(G_OBJECT(pad),
711 pad_signals[BUFFER_SIZE_CHANGED], 0,
712 buffer_size,
713 old_buffer_size);
714 g_object_unref((GObject *) pad);
715 }
716
717 /**
718 * ags_pad_format_changed:
719 * @pad: the #AgsPad
720 * @format: the format
721 * @old_format: the old format
722 *
723 * Notify about format changed.
724 *
725 * Since: 3.0.0
726 */
727 void
ags_pad_format_changed(AgsPad * pad,guint format,guint old_format)728 ags_pad_format_changed(AgsPad *pad,
729 guint format, guint old_format)
730 {
731 g_return_if_fail(AGS_IS_PAD(pad));
732
733 g_object_ref((GObject *) pad);
734 g_signal_emit(G_OBJECT(pad),
735 pad_signals[FORMAT_CHANGED], 0,
736 format,
737 old_format);
738 g_object_unref((GObject *) pad);
739 }
740
741 void
ags_pad_real_set_channel(AgsPad * pad,AgsChannel * channel)742 ags_pad_real_set_channel(AgsPad *pad, AgsChannel *channel)
743 {
744 AgsChannel *current, *next_current;
745
746 GList *line, *line_start;
747
748 if(pad->channel == channel){
749 return;
750 }
751
752 if(pad->channel != NULL){
753 g_object_unref(G_OBJECT(pad->channel));
754 }
755
756 if(channel != NULL){
757 g_object_ref(G_OBJECT(channel));
758 }
759
760 if(channel != NULL){
761 pad->samplerate = channel->samplerate;
762 pad->buffer_size = channel->buffer_size;
763 pad->format = channel->format;
764 }
765
766 pad->channel = channel;
767
768 line_start =
769 line = gtk_container_get_children(GTK_CONTAINER(AGS_PAD(pad)->expander_set));
770
771 current = channel;
772
773 if(current != NULL){
774 g_object_ref(current);
775 }
776
777 next_current = NULL;
778
779 /* set channel */
780 while(line != NULL){
781 g_object_set(G_OBJECT(line->data),
782 "channel", current,
783 NULL);
784
785 /* iterate */
786 if(current != NULL){
787 next_current = ags_channel_next(current);
788
789 g_object_unref(current);
790
791 current = next_current;
792 }
793
794 line = line->next;
795 }
796
797 if(next_current != NULL){
798 g_object_unref(next_current);
799 }
800
801 g_list_free(line_start);
802 }
803
804 /**
805 * ags_pad_set_channel:
806 * @pad: an #AgsPad
807 * @channel: the #AgsChannel to set
808 *
809 * Is emitted as channel gets modified.
810 *
811 * Since: 3.0.0
812 */
813 void
ags_pad_set_channel(AgsPad * pad,AgsChannel * channel)814 ags_pad_set_channel(AgsPad *pad, AgsChannel *channel)
815 {
816 g_return_if_fail(AGS_IS_PAD(pad));
817
818 g_object_ref((GObject *) pad);
819 g_signal_emit(G_OBJECT(pad),
820 pad_signals[SET_CHANNEL], 0,
821 channel);
822 g_object_unref((GObject *) pad);
823 }
824
825 void
ags_pad_real_resize_lines(AgsPad * pad,GType line_type,guint audio_channels,guint audio_channels_old)826 ags_pad_real_resize_lines(AgsPad *pad, GType line_type,
827 guint audio_channels, guint audio_channels_old)
828 {
829 AgsLine *line;
830
831 AgsAudio *audio;
832 AgsChannel *channel;
833
834 guint audio_audio_channels;
835 guint i;
836
837 #ifdef AGS_DEBUG
838 g_message("ags_pad_real_resize_lines: audio_channels = %u ; audio_channels_old = %u\n", audio_channels, audio_channels_old);
839 #endif
840
841 audio = NULL;
842
843 audio_audio_channels = 0;
844
845 if(pad->channel != NULL){
846 g_object_get(pad->channel,
847 "audio", &audio,
848 NULL);
849 }
850
851 if(audio != NULL){
852 g_object_get(audio,
853 "audio-channels", &audio_audio_channels,
854 NULL);
855 }
856
857 /* resize */
858 if(audio_channels > audio_channels_old){
859 /* create AgsLine */
860 for(i = audio_channels_old; i < audio_channels; i++){
861 /* instantiate line */
862 if(i < audio_audio_channels){
863 channel = ags_channel_nth(pad->channel,
864 i);
865 }else{
866 channel = NULL;
867 }
868
869 line = (AgsLine *) g_object_new(line_type,
870 "pad", pad,
871 "channel", channel,
872 NULL);
873
874 if(channel != NULL){
875 channel->line_widget = (GObject *) line;
876 }
877
878 ags_expander_set_add(pad->expander_set,
879 (GtkWidget *) line,
880 i % pad->cols, floor(i / pad->cols),
881 1, 1);
882
883 if(channel != NULL){
884 g_object_unref(channel);
885 }
886 }
887 }else if(audio_channels < audio_channels_old){
888 GList *list, *list_start;
889
890 list_start =
891 list = g_list_nth(g_list_reverse(gtk_container_get_children(GTK_CONTAINER(pad->expander_set))),
892 audio_channels);
893
894 while(list != NULL){
895 ags_connectable_disconnect(AGS_CONNECTABLE(list->data));
896
897 list = list->next;
898 }
899
900 list = list_start;
901
902 while(list != NULL){
903 gtk_widget_destroy(GTK_WIDGET(list->data));
904
905 list = list->next;
906 }
907
908 g_list_free(list_start);
909 }
910
911 if(audio != NULL){
912 g_object_unref(audio);
913 }
914 }
915
916 /**
917 * ags_pad_resize_lines:
918 * @pad: the #AgsPad to resize
919 * @line_type: channel type, either %AGS_TYPE_INPUT or %AGS_TYPE_OUTPUT
920 * @audio_channels: count of lines
921 * @audio_channels_old: old count of lines
922 *
923 * Resize the count of #AgsLine packe by #AgsPad.
924 *
925 * Since: 3.0.0
926 */
927 void
ags_pad_resize_lines(AgsPad * pad,GType line_type,guint audio_channels,guint audio_channels_old)928 ags_pad_resize_lines(AgsPad *pad, GType line_type,
929 guint audio_channels, guint audio_channels_old)
930 {
931 g_return_if_fail(AGS_IS_PAD(pad));
932
933 // fprintf(stdout, "ags_pad_resize_lines: audio_channels = %u ; audio_channels_old = %u\n", audio_channels, audio_channels_old);
934
935 g_object_ref((GObject *) pad);
936 g_signal_emit(G_OBJECT(pad),
937 pad_signals[RESIZE_LINES], 0,
938 line_type,
939 audio_channels, audio_channels_old);
940 g_object_unref((GObject *) pad);
941 }
942
943 void
ags_pad_real_map_recall(AgsPad * pad,guint output_pad_start)944 ags_pad_real_map_recall(AgsPad *pad, guint output_pad_start)
945 {
946 if((AGS_PAD_MAPPED_RECALL & (pad->flags)) != 0){
947 return;
948 }
949
950 pad->flags |= AGS_PAD_MAPPED_RECALL;
951
952 ags_pad_find_port(pad);
953 }
954
955 /**
956 * ags_pad_map_recall:
957 * @pad: the #AgsPad to resize
958 * @output_pad_start: start of output pad
959 *
960 * Start of output pad
961 *
962 * Since: 3.0.0
963 */
964 void
ags_pad_map_recall(AgsPad * pad,guint output_pad_start)965 ags_pad_map_recall(AgsPad *pad, guint output_pad_start)
966 {
967 g_return_if_fail(AGS_IS_PAD(pad));
968
969 g_object_ref((GObject *) pad);
970 g_signal_emit(G_OBJECT(pad),
971 pad_signals[MAP_RECALL], 0,
972 output_pad_start);
973 g_object_unref((GObject *) pad);
974 }
975
976 GList*
ags_pad_real_find_port(AgsPad * pad)977 ags_pad_real_find_port(AgsPad *pad)
978 {
979 GList *start_line, *line;
980
981 GList *port, *tmp_port;
982
983 port = NULL;
984
985 /* find output ports */
986 if(pad->expander_set != NULL){
987 line =
988 start_line = gtk_container_get_children((GtkContainer *) pad->expander_set);
989
990 while(line != NULL){
991 tmp_port = ags_line_find_port(AGS_LINE(line->data));
992
993 if(port != NULL){
994 port = g_list_concat(port,
995 tmp_port);
996 }else{
997 port = tmp_port;
998 }
999
1000 line = line->next;
1001 }
1002
1003 g_list_free(start_line);
1004 }
1005
1006 return(port);
1007 }
1008
1009 /**
1010 * ags_pad_find_port:
1011 * @pad: an #AgsPad
1012 *
1013 * Lookup ports of assigned recalls.
1014 *
1015 * Returns: an #GList containing all related #AgsPort
1016 *
1017 * Since: 3.0.0
1018 */
1019 GList*
ags_pad_find_port(AgsPad * pad)1020 ags_pad_find_port(AgsPad *pad)
1021 {
1022 GList *list;
1023
1024 list = NULL;
1025 g_return_val_if_fail(AGS_IS_PAD(pad),
1026 NULL);
1027
1028 g_object_ref((GObject *) pad);
1029 g_signal_emit((GObject *) pad,
1030 pad_signals[FIND_PORT], 0,
1031 &list);
1032 g_object_unref((GObject *) pad);
1033
1034 return(list);
1035 }
1036
1037 void
ags_pad_play(AgsPad * pad)1038 ags_pad_play(AgsPad *pad)
1039 {
1040 AgsMachine *machine;
1041
1042 AgsChannel *channel;
1043 AgsChannel *next_pad, *next_channel;
1044 AgsPlayback *playback;
1045
1046 GList *start_list, *list;
1047
1048 gboolean play_all;
1049
1050 if(!AGS_IS_PAD(pad)){
1051 return;
1052 }
1053
1054 machine = (AgsMachine *) gtk_widget_get_ancestor((GtkWidget *) pad,
1055 AGS_TYPE_MACHINE);
1056
1057 list =
1058 start_list = gtk_container_get_children(GTK_CONTAINER(pad->expander_set));
1059
1060 /* */
1061 play_all = gtk_toggle_button_get_active(pad->group);
1062
1063 if(gtk_toggle_button_get_active(pad->play)){
1064 if(play_all){
1065 channel = pad->channel;
1066
1067 if(channel != NULL){
1068 g_object_ref(channel);
1069 }
1070
1071 next_pad = ags_channel_next_pad(channel);
1072 next_channel = NULL;
1073
1074 while(channel != next_pad){
1075 AgsNote *play_note;
1076
1077 g_object_get(channel,
1078 "playback", &playback,
1079 NULL);
1080
1081 g_object_get(playback,
1082 "play-note", &play_note,
1083 NULL);
1084
1085 g_object_set(play_note,
1086 "x0", 0,
1087 "x1", 1,
1088 NULL);
1089
1090 ags_machine_playback_set_active(machine,
1091 playback,
1092 TRUE);
1093
1094 g_object_unref(playback);
1095
1096 /* iterate */
1097 next_channel = ags_channel_next(channel);
1098
1099 g_object_unref(channel);
1100
1101 channel = next_channel;
1102 }
1103
1104 /* unref */
1105 if(next_pad != NULL){
1106 g_object_unref(next_pad);
1107 }
1108
1109 if(next_channel != NULL){
1110 g_object_unref(next_channel);
1111 }
1112 }else{
1113 while((list = ags_line_find_next_grouped(list)) != NULL){
1114 AgsLine *line;
1115
1116 line = AGS_LINE(list->data);
1117
1118 channel = line->channel;
1119
1120 g_object_get(channel,
1121 "playback", &playback,
1122 NULL);
1123
1124 ags_machine_playback_set_active(machine,
1125 playback,
1126 TRUE);
1127
1128 g_object_unref(playback);
1129
1130 /* iterate */
1131 list = list->next;
1132 }
1133 }
1134 }else{
1135 if(play_all){
1136 channel = pad->channel;
1137
1138 if(channel != NULL){
1139 g_object_ref(channel);
1140 }
1141
1142 next_pad = ags_channel_next_pad(channel);
1143 next_channel = NULL;
1144
1145 while(channel != next_pad){
1146 g_object_get(channel,
1147 "playback", &playback,
1148 NULL);
1149
1150 ags_machine_playback_set_active(machine,
1151 playback,
1152 FALSE);
1153
1154 g_object_unref(playback);
1155
1156 /* iterate */
1157 next_channel = ags_channel_next(channel);
1158
1159 g_object_unref(channel);
1160
1161 channel = next_channel;
1162 }
1163
1164 /* unref */
1165 if(next_pad != NULL){
1166 g_object_unref(next_pad);
1167 }
1168
1169 if(next_channel != NULL){
1170 g_object_unref(next_channel);
1171 }
1172 }else{
1173 while((list = ags_line_find_next_grouped(list)) != NULL){
1174 AgsLine *line;
1175
1176 line = AGS_LINE(list->data);
1177
1178 channel = line->channel;
1179
1180 g_object_get(channel,
1181 "playback", &playback,
1182 NULL);
1183
1184 ags_machine_playback_set_active(machine,
1185 playback,
1186 FALSE);
1187
1188 g_object_unref(playback);
1189
1190 /* iterate */
1191 list = list->next;
1192 }
1193 }
1194 }
1195
1196 g_list_free(start_list);
1197 }
1198
1199 /**
1200 * ags_pad_new:
1201 * @channel: the bunch of channel to visualize
1202 *
1203 * Creates an #AgsPad
1204 *
1205 * Returns: a new #AgsPad
1206 *
1207 * Since: 3.0.0
1208 */
1209 AgsPad*
ags_pad_new(AgsChannel * channel)1210 ags_pad_new(AgsChannel *channel)
1211 {
1212 AgsPad *pad;
1213
1214 pad = (AgsPad *) g_object_new(AGS_TYPE_PAD, NULL);
1215
1216 return(pad);
1217 }
1218