1 /* GSequencer - Advanced GTK Sequencer
2 * Copyright (C) 2005-2020 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_effect_line.h>
21 #include <ags/X/ags_effect_line_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_effect_pad.h>
27 #include <ags/X/ags_line_member.h>
28 #include <ags/X/ags_effect_separator.h>
29 #include <ags/X/ags_machine_editor.h>
30 #include <ags/X/ags_pad_editor.h>
31 #include <ags/X/ags_line_editor.h>
32 #include <ags/X/ags_line_member_editor.h>
33 #include <ags/X/ags_plugin_browser.h>
34 #include <ags/X/ags_ladspa_browser.h>
35 #include <ags/X/ags_dssi_browser.h>
36 #include <ags/X/ags_lv2_browser.h>
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <sys/types.h>
42 #include <unistd.h>
43
44 #include <ladspa.h>
45
46 #include <ags/i18n.h>
47
48 void ags_effect_line_class_init(AgsEffectLineClass *effect_line);
49 void ags_effect_line_connectable_interface_init(AgsConnectableInterface *connectable);
50 void ags_effect_line_init(AgsEffectLine *effect_line);
51 void ags_effect_line_set_property(GObject *gobject,
52 guint prop_id,
53 const GValue *value,
54 GParamSpec *param_spec);
55 void ags_effect_line_get_property(GObject *gobject,
56 guint prop_id,
57 GValue *value,
58 GParamSpec *param_spec);
59 void ags_effect_line_dispose(GObject *gobject);
60 void ags_effect_line_finalize(GObject *gobject);
61
62 void ags_effect_line_connect(AgsConnectable *connectable);
63 void ags_effect_line_disconnect(AgsConnectable *connectable);
64
65 void ags_effect_line_real_set_channel(AgsEffectLine *effect_line, AgsChannel *channel);
66
67 void ags_effect_line_add_ladspa_plugin(AgsEffectLine *effect_line,
68 GList *control_type_name,
69 AgsRecallContainer *play_container, AgsRecallContainer *recall_container,
70 gchar *plugin_name,
71 gchar *filename,
72 gchar *effect,
73 guint start_audio_channel, guint stop_audio_channel,
74 guint start_pad, guint stop_pad,
75 gint position,
76 guint create_flags, guint recall_flags);
77 void ags_effect_line_add_dssi_plugin(AgsEffectLine *effect_line,
78 GList *control_type_name,
79 AgsRecallContainer *play_container, AgsRecallContainer *recall_container,
80 gchar *plugin_name,
81 gchar *filename,
82 gchar *effect,
83 guint start_audio_channel, guint stop_audio_channel,
84 guint start_pad, guint stop_pad,
85 gint position,
86 guint create_flags, guint recall_flags);
87 void ags_effect_line_add_lv2_plugin(AgsEffectLine *effect_line,
88 GList *control_type_name,
89 AgsRecallContainer *play_container, AgsRecallContainer *recall_container,
90 gchar *plugin_name,
91 gchar *filename,
92 gchar *effect,
93 guint start_audio_channel, guint stop_audio_channel,
94 guint start_pad, guint stop_pad,
95 gint position,
96 guint create_flags, guint recall_flags);
97 void ags_effect_line_real_add_plugin(AgsEffectLine *effect_line,
98 GList *control_type_name,
99 AgsRecallContainer *play_container, AgsRecallContainer *recall_container,
100 gchar *plugin_name,
101 gchar *filename,
102 gchar *effect,
103 guint start_audio_channel, guint stop_audio_channel,
104 guint start_pad, guint stop_pad,
105 gint position,
106 guint create_flags, guint recall_flags);
107 void ags_effect_line_real_remove_plugin(AgsEffectLine *effect_line,
108 guint nth);
109
110 void ags_effect_line_real_map_recall(AgsEffectLine *effect_line,
111 guint output_pad_start);
112 GList* ags_effect_line_real_find_port(AgsEffectLine *effect_line);
113
114 /**
115 * SECTION:ags_effect_line
116 * @short_description: A composite widget to visualize a bunch of #AgsChannel
117 * @title: AgsEffectLine
118 * @section_id:
119 * @include: ags/X/ags_effect_line.h
120 *
121 * #AgsEffectLine is a composite widget to visualize one #AgsChannel. It should be
122 * packed by an #AgsEffectLine.
123 */
124
125 enum{
126 SAMPLERATE_CHANGED,
127 BUFFER_SIZE_CHANGED,
128 FORMAT_CHANGED,
129 SET_CHANNEL,
130 ADD_PLUGIN,
131 REMOVE_PLUGIN,
132 MAP_RECALL,
133 FIND_PORT,
134 DONE,
135 LAST_SIGNAL,
136 };
137
138 enum{
139 PROP_0,
140 PROP_SAMPLERATE,
141 PROP_BUFFER_SIZE,
142 PROP_FORMAT,
143 PROP_CHANNEL,
144 };
145
146 static gpointer ags_effect_line_parent_class = NULL;
147 static guint effect_line_signals[LAST_SIGNAL];
148
149 GHashTable *ags_effect_line_indicator_queue_draw = NULL;
150
151 GType
ags_effect_line_get_type(void)152 ags_effect_line_get_type(void)
153 {
154 static volatile gsize g_define_type_id__volatile = 0;
155
156 if(g_once_init_enter (&g_define_type_id__volatile)){
157 GType ags_type_effect_line = 0;
158
159 static const GTypeInfo ags_effect_line_info = {
160 sizeof(AgsEffectLineClass),
161 NULL, /* base_init */
162 NULL, /* base_finalize */
163 (GClassInitFunc) ags_effect_line_class_init,
164 NULL, /* class_finalize */
165 NULL, /* class_data */
166 sizeof(AgsEffectLine),
167 0, /* n_preallocs */
168 (GInstanceInitFunc) ags_effect_line_init,
169 };
170
171 static const GInterfaceInfo ags_connectable_interface_info = {
172 (GInterfaceInitFunc) ags_effect_line_connectable_interface_init,
173 NULL, /* interface_finalize */
174 NULL, /* interface_data */
175 };
176
177 ags_type_effect_line = g_type_register_static(GTK_TYPE_BOX,
178 "AgsEffectLine", &ags_effect_line_info,
179 0);
180
181 g_type_add_interface_static(ags_type_effect_line,
182 AGS_TYPE_CONNECTABLE,
183 &ags_connectable_interface_info);
184
185 g_once_init_leave(&g_define_type_id__volatile, ags_type_effect_line);
186 }
187
188 return g_define_type_id__volatile;
189 }
190
191 void
ags_effect_line_class_init(AgsEffectLineClass * effect_line)192 ags_effect_line_class_init(AgsEffectLineClass *effect_line)
193 {
194 GObjectClass *gobject;
195 GParamSpec *param_spec;
196
197 ags_effect_line_parent_class = g_type_class_peek_parent(effect_line);
198
199 /* GObjectClass */
200 gobject = G_OBJECT_CLASS(effect_line);
201
202 gobject->set_property = ags_effect_line_set_property;
203 gobject->get_property = ags_effect_line_get_property;
204
205 gobject->dispose = ags_effect_line_dispose;
206 gobject->finalize = ags_effect_line_finalize;
207
208 /* properties */
209 /**
210 * AgsEffectLine:samplerate:
211 *
212 * The samplerate.
213 *
214 * Since: 3.0.0
215 */
216 param_spec = g_param_spec_uint("samplerate",
217 i18n_pspec("samplerate"),
218 i18n_pspec("The samplerate"),
219 0,
220 G_MAXUINT32,
221 AGS_SOUNDCARD_DEFAULT_SAMPLERATE,
222 G_PARAM_READABLE | G_PARAM_WRITABLE);
223 g_object_class_install_property(gobject,
224 PROP_SAMPLERATE,
225 param_spec);
226
227 /**
228 * AgsEffectLine:buffer-size:
229 *
230 * The buffer length.
231 *
232 * Since: 3.0.0
233 */
234 param_spec = g_param_spec_uint("buffer-size",
235 i18n_pspec("buffer size"),
236 i18n_pspec("The buffer size"),
237 0,
238 G_MAXUINT32,
239 AGS_SOUNDCARD_DEFAULT_BUFFER_SIZE,
240 G_PARAM_READABLE | G_PARAM_WRITABLE);
241 g_object_class_install_property(gobject,
242 PROP_BUFFER_SIZE,
243 param_spec);
244
245 /**
246 * AgsEffectLine:format:
247 *
248 * The format.
249 *
250 * Since: 3.0.0
251 */
252 param_spec = g_param_spec_uint("format",
253 i18n_pspec("format"),
254 i18n_pspec("The format"),
255 0,
256 G_MAXUINT32,
257 AGS_SOUNDCARD_DEFAULT_FORMAT,
258 G_PARAM_READABLE | G_PARAM_WRITABLE);
259 g_object_class_install_property(gobject,
260 PROP_FORMAT,
261 param_spec);
262
263 /**
264 * AgsEffectLine:channel:
265 *
266 * The start of a bunch of #AgsChannel to visualize.
267 *
268 * Since: 3.0.0
269 */
270 param_spec = g_param_spec_object("channel",
271 i18n_pspec("assigned channel"),
272 i18n_pspec("The channel it is assigned with"),
273 AGS_TYPE_CHANNEL,
274 G_PARAM_READABLE | G_PARAM_WRITABLE);
275 g_object_class_install_property(gobject,
276 PROP_CHANNEL,
277 param_spec);
278
279 /* AgsEffectLineClass */
280 effect_line->samplerate_changed = NULL;
281 effect_line->buffer_size_changed = NULL;
282 effect_line->format_changed = NULL;
283
284 effect_line->set_channel = ags_effect_line_real_set_channel;
285
286 effect_line->add_plugin = ags_effect_line_real_add_plugin;
287 effect_line->remove_plugin = ags_effect_line_real_remove_plugin;
288
289 effect_line->map_recall = ags_effect_line_real_map_recall;
290 effect_line->find_port = ags_effect_line_real_find_port;
291
292 effect_line->done = NULL;
293
294 /* signals */
295 /**
296 * AgsEffectLine::samplerate-changed:
297 * @effect_line: the #AgsEffectLine
298 * @samplerate: the samplerate
299 * @old_samplerate: the old samplerate
300 *
301 * The ::samplerate-changed signal notifies about changed samplerate.
302 *
303 * Since: 3.0.0
304 */
305 effect_line_signals[SAMPLERATE_CHANGED] =
306 g_signal_new("samplerate-changed",
307 G_TYPE_FROM_CLASS(effect_line),
308 G_SIGNAL_RUN_LAST,
309 G_STRUCT_OFFSET(AgsEffectLineClass, samplerate_changed),
310 NULL, NULL,
311 ags_cclosure_marshal_VOID__UINT_UINT,
312 G_TYPE_NONE, 2,
313 G_TYPE_UINT,
314 G_TYPE_UINT);
315
316 /**
317 * AgsEffectLine::buffer-size-changed:
318 * @effect_line: the #AgsEffectLine
319 * @buffer_size: the buffer size
320 * @old_buffer_size: the old buffer size
321 *
322 * The ::buffer-size-changed signal notifies about changed buffer size.
323 *
324 * Since: 3.0.0
325 */
326 effect_line_signals[BUFFER_SIZE_CHANGED] =
327 g_signal_new("buffer-size-changed",
328 G_TYPE_FROM_CLASS(effect_line),
329 G_SIGNAL_RUN_LAST,
330 G_STRUCT_OFFSET(AgsEffectLineClass, buffer_size_changed),
331 NULL, NULL,
332 ags_cclosure_marshal_VOID__UINT_UINT,
333 G_TYPE_NONE, 2,
334 G_TYPE_UINT,
335 G_TYPE_UINT);
336
337 /**
338 * AgsEffectLine::format-changed:
339 * @effect_line: the #AgsEffectLine
340 * @format: the format
341 * @old_format: the old format
342 *
343 * The ::format-changed signal notifies about changed format.
344 *
345 * Since: 3.0.0
346 */
347 effect_line_signals[FORMAT_CHANGED] =
348 g_signal_new("format-changed",
349 G_TYPE_FROM_CLASS(effect_line),
350 G_SIGNAL_RUN_LAST,
351 G_STRUCT_OFFSET(AgsEffectLineClass, format_changed),
352 NULL, NULL,
353 ags_cclosure_marshal_VOID__UINT_UINT,
354 G_TYPE_NONE, 2,
355 G_TYPE_UINT,
356 G_TYPE_UINT);
357
358 /**
359 * AgsEffectLine::set-channel:
360 * @effect_line: the #AgsEffectLine to modify
361 * @channel: the #AgsChannel to set
362 *
363 * The ::set-channel signal notifies about changed channel.
364 *
365 * Since: 3.0.0
366 */
367 effect_line_signals[SET_CHANNEL] =
368 g_signal_new("set-channel",
369 G_TYPE_FROM_CLASS(effect_line),
370 G_SIGNAL_RUN_LAST,
371 G_STRUCT_OFFSET(AgsEffectLineClass, set_channel),
372 NULL, NULL,
373 g_cclosure_marshal_VOID__OBJECT,
374 G_TYPE_NONE, 1,
375 G_TYPE_OBJECT);
376
377 /**
378 * AgsEffectLine::add-plugin:
379 * @effect_line: the #AgsEffectLine to modify
380 * @effect: the effect's name
381 *
382 * The ::add-plugin signal notifies about added effect.
383 *
384 * Since: 3.3.0
385 */
386 effect_line_signals[ADD_PLUGIN] =
387 g_signal_new("add-plugin",
388 G_TYPE_FROM_CLASS(effect_line),
389 G_SIGNAL_RUN_LAST,
390 G_STRUCT_OFFSET(AgsEffectLineClass, add_plugin),
391 NULL, NULL,
392 ags_cclosure_marshal_VOID__POINTER_OBJECT_OBJECT_STRING_STRING_STRING_UINT_UINT_UINT_UINT_INT_UINT_UINT,
393 G_TYPE_NONE, 13,
394 G_TYPE_POINTER,
395 G_TYPE_OBJECT,
396 G_TYPE_OBJECT,
397 G_TYPE_STRING,
398 G_TYPE_STRING,
399 G_TYPE_STRING,
400 G_TYPE_UINT,
401 G_TYPE_UINT,
402 G_TYPE_UINT,
403 G_TYPE_UINT,
404 G_TYPE_INT,
405 G_TYPE_UINT,
406 G_TYPE_UINT);
407
408 /**
409 * AgsEffectLine::remove-plugin:
410 * @effect_line: the #AgsEffectLine to modify
411 * @nth: the nth effect
412 *
413 * The ::remove-plugin signal notifies about removed effect.
414 *
415 * Since: 3.3.0
416 */
417 effect_line_signals[REMOVE_PLUGIN] =
418 g_signal_new("remove-plugin",
419 G_TYPE_FROM_CLASS(effect_line),
420 G_SIGNAL_RUN_LAST,
421 G_STRUCT_OFFSET(AgsEffectLineClass, remove_plugin),
422 NULL, NULL,
423 g_cclosure_marshal_VOID__UINT,
424 G_TYPE_NONE, 1,
425 G_TYPE_UINT);
426
427 /**
428 * AgsEffectLine::map-recall:
429 * @effect_line: the #AgsEffectLine
430 * @output_pad_start: the channel's start pad
431 *
432 * The ::map-recall should be used to add the effect_line's default recall. This function
433 * may call ags_effect_line_find_port().
434 *
435 * Since: 3.0.0
436 */
437 effect_line_signals[MAP_RECALL] =
438 g_signal_new("map-recall",
439 G_TYPE_FROM_CLASS (effect_line),
440 G_SIGNAL_RUN_LAST,
441 G_STRUCT_OFFSET (AgsEffectLineClass, map_recall),
442 NULL, NULL,
443 g_cclosure_marshal_VOID__UINT,
444 G_TYPE_NONE, 1,
445 G_TYPE_UINT);
446
447 /**
448 * AgsEffectLine::find-port:
449 * @effect_line: the #AgsEffectLine to resize
450 *
451 * The ::find-port as recall should be mapped
452 *
453 * Returns: an #GList-struct containing all related #AgsPort
454 *
455 * Since: 3.0.0
456 */
457 effect_line_signals[FIND_PORT] =
458 g_signal_new("find-port",
459 G_TYPE_FROM_CLASS(effect_line),
460 G_SIGNAL_RUN_LAST,
461 G_STRUCT_OFFSET(AgsEffectLineClass, find_port),
462 NULL, NULL,
463 ags_cclosure_marshal_POINTER__VOID,
464 G_TYPE_POINTER, 0);
465
466 /**
467 * AgsEffectLine::done:
468 * @effect_line: the #AgsEffectLine
469 * @recall_id: the #AgsRecallID
470 *
471 * The ::done signal gets emited as audio stops playback.
472 *
473 * Since: 3.0.0
474 */
475 effect_line_signals[DONE] =
476 g_signal_new("done",
477 G_TYPE_FROM_CLASS(effect_line),
478 G_SIGNAL_RUN_LAST,
479 G_STRUCT_OFFSET(AgsEffectLineClass, done),
480 NULL, NULL,
481 g_cclosure_marshal_VOID__OBJECT,
482 G_TYPE_NONE, 1,
483 G_TYPE_OBJECT);
484 }
485
486 void
ags_effect_line_connectable_interface_init(AgsConnectableInterface * connectable)487 ags_effect_line_connectable_interface_init(AgsConnectableInterface *connectable)
488 {
489 connectable->is_ready = NULL;
490 connectable->is_connected = NULL;
491 connectable->connect = ags_effect_line_connect;
492 connectable->disconnect = ags_effect_line_disconnect;
493 }
494
495 void
ags_effect_line_init(AgsEffectLine * effect_line)496 ags_effect_line_init(AgsEffectLine *effect_line)
497 {
498 AgsApplicationContext *application_context;
499 AgsConfig *config;
500
501 gtk_orientable_set_orientation(GTK_ORIENTABLE(effect_line),
502 GTK_ORIENTATION_VERTICAL);
503
504 application_context = ags_application_context_get_instance();
505
506 g_signal_connect(application_context, "check-message",
507 G_CALLBACK(ags_effect_line_check_message_callback), effect_line);
508
509 if(ags_effect_line_indicator_queue_draw == NULL){
510 ags_effect_line_indicator_queue_draw = g_hash_table_new_full(g_direct_hash, g_direct_equal,
511 NULL,
512 NULL);
513 }
514
515 effect_line->flags = 0;
516
517 effect_line->name = NULL;
518
519 effect_line->version = AGS_EFFECT_LINE_DEFAULT_VERSION;
520 effect_line->build_id = AGS_EFFECT_LINE_DEFAULT_BUILD_ID;
521
522 config = ags_config_get_instance();
523
524 effect_line->samplerate = ags_soundcard_helper_config_get_samplerate(config);
525 effect_line->buffer_size = ags_soundcard_helper_config_get_buffer_size(config);
526 effect_line->format = ags_soundcard_helper_config_get_format(config);
527
528 effect_line->channel = NULL;
529
530 effect_line->label = (GtkLabel *) g_object_new(GTK_TYPE_LABEL,
531 NULL);
532 gtk_box_pack_start(GTK_BOX(effect_line),
533 GTK_WIDGET(effect_line->label),
534 FALSE, FALSE,
535 0);
536
537 effect_line->group = (GtkToggleButton *) gtk_toggle_button_new_with_label(i18n("group"));
538 gtk_box_pack_start((GtkBox *) effect_line,
539 (GtkWidget *) effect_line->group,
540 FALSE, FALSE,
541 0);
542
543 effect_line->grid = (GtkGrid *) gtk_grid_new();
544 gtk_box_pack_start((GtkBox *) effect_line,
545 (GtkWidget *) effect_line->grid,
546 FALSE, FALSE,
547 0);
548
549 effect_line->plugin = NULL;
550
551 effect_line->queued_drawing = NULL;
552 }
553
554 void
ags_effect_line_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)555 ags_effect_line_set_property(GObject *gobject,
556 guint prop_id,
557 const GValue *value,
558 GParamSpec *param_spec)
559 {
560 AgsEffectLine *effect_line;
561
562 effect_line = AGS_EFFECT_LINE(gobject);
563
564 switch(prop_id){
565 case PROP_SAMPLERATE:
566 {
567 guint samplerate, old_samplerate;
568
569 samplerate = g_value_get_uint(value);
570 old_samplerate = effect_line->samplerate;
571
572 if(samplerate == old_samplerate){
573 return;
574 }
575
576 effect_line->samplerate = samplerate;
577
578 ags_effect_line_samplerate_changed(effect_line,
579 samplerate, old_samplerate);
580 }
581 break;
582 case PROP_BUFFER_SIZE:
583 {
584 guint buffer_size, old_buffer_size;
585
586 buffer_size = g_value_get_uint(value);
587 old_buffer_size = effect_line->buffer_size;
588
589 if(buffer_size == old_buffer_size){
590 return;
591 }
592
593 effect_line->buffer_size = buffer_size;
594
595 ags_effect_line_buffer_size_changed(effect_line,
596 buffer_size, old_buffer_size);
597 }
598 break;
599 case PROP_FORMAT:
600 {
601 guint format, old_format;
602
603 format = g_value_get_uint(value);
604 old_format = effect_line->format;
605
606 if(format == old_format){
607 return;
608 }
609
610 effect_line->format = format;
611
612 ags_effect_line_format_changed(effect_line,
613 format, old_format);
614 }
615 break;
616 case PROP_CHANNEL:
617 {
618 AgsChannel *channel;
619
620 channel = (AgsChannel *) g_value_get_object(value);
621
622 ags_effect_line_set_channel(effect_line, channel);
623 }
624 break;
625 default:
626 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
627 break;
628 }
629 }
630
631 void
ags_effect_line_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)632 ags_effect_line_get_property(GObject *gobject,
633 guint prop_id,
634 GValue *value,
635 GParamSpec *param_spec)
636 {
637 AgsEffectLine *effect_line;
638
639 effect_line = AGS_EFFECT_LINE(gobject);
640
641 switch(prop_id){
642 case PROP_SAMPLERATE:
643 {
644 g_value_set_uint(value,
645 effect_line->samplerate);
646 }
647 break;
648 case PROP_BUFFER_SIZE:
649 {
650 g_value_set_uint(value,
651 effect_line->buffer_size);
652 }
653 break;
654 case PROP_FORMAT:
655 {
656 g_value_set_uint(value,
657 effect_line->format);
658 }
659 break;
660 case PROP_CHANNEL:
661 {
662 g_value_set_object(value,
663 effect_line->channel);
664 }
665 break;
666 default:
667 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
668 break;
669 }
670 }
671
672 void
ags_effect_line_dispose(GObject * gobject)673 ags_effect_line_dispose(GObject *gobject)
674 {
675 AgsEffectLine *effect_line;
676
677 effect_line = AGS_EFFECT_LINE(gobject);
678
679 if(effect_line->channel != NULL){
680 g_object_unref(effect_line->channel);
681
682 effect_line->channel = NULL;
683 }
684
685 /* call parent */
686 G_OBJECT_CLASS(ags_effect_line_parent_class)->dispose(gobject);
687 }
688
689 void
ags_effect_line_finalize(GObject * gobject)690 ags_effect_line_finalize(GObject *gobject)
691 {
692 AgsEffectLine *effect_line;
693
694 AgsApplicationContext *application_context;
695
696 GList *list;
697
698 effect_line = AGS_EFFECT_LINE(gobject);
699
700 application_context = ags_application_context_get_instance();
701
702 g_object_disconnect(application_context,
703 "any_signal::check-message",
704 G_CALLBACK(ags_effect_line_check_message_callback),
705 effect_line,
706 NULL);
707
708 /* remove of the queued drawing hash */
709 list = effect_line->queued_drawing;
710
711 while(list != NULL){
712 g_hash_table_remove(ags_effect_line_indicator_queue_draw,
713 list->data);
714
715 list = list->next;
716 }
717
718 /* channel */
719 if(effect_line->channel != NULL){
720 g_object_unref(effect_line->channel);
721 }
722
723 /* call parent */
724 G_OBJECT_CLASS(ags_effect_line_parent_class)->finalize(gobject);
725 }
726
727 void
ags_effect_line_connect(AgsConnectable * connectable)728 ags_effect_line_connect(AgsConnectable *connectable)
729 {
730 AgsEffectLine *effect_line;
731
732 GList *list, *start_list;
733
734 effect_line = AGS_EFFECT_LINE(connectable);
735
736 if((AGS_EFFECT_LINE_CONNECTED & (effect_line->flags)) == 0){
737 return;
738 }
739
740 effect_line->flags &= (~AGS_EFFECT_LINE_CONNECTED);
741
742 if((AGS_EFFECT_LINE_PREMAPPED_RECALL & (effect_line->flags)) == 0){
743 if((AGS_EFFECT_LINE_MAPPED_RECALL & (effect_line->flags)) == 0){
744 ags_effect_line_map_recall(effect_line,
745 0);
746 }
747 }else{
748 ags_effect_line_find_port(effect_line);
749 }
750
751 /* connect line members */
752 list =
753 start_list = gtk_container_get_children(GTK_CONTAINER(effect_line->grid));
754
755 while(list != NULL){
756 if(AGS_IS_CONNECTABLE(list->data)){
757 ags_connectable_disconnect(AGS_CONNECTABLE(list->data));
758 }
759
760 list = list->next;
761 }
762
763 g_list_free(start_list);
764 }
765
766 void
ags_effect_line_disconnect(AgsConnectable * connectable)767 ags_effect_line_disconnect(AgsConnectable *connectable)
768 {
769 AgsEffectLine *effect_line;
770
771 GList *start_list, *list;
772
773 effect_line = AGS_EFFECT_LINE(connectable);
774
775 if((AGS_EFFECT_LINE_CONNECTED & (effect_line->flags)) == 0){
776 return;
777 }
778
779 /* unset connected flag */
780 effect_line->flags &= (~AGS_EFFECT_LINE_CONNECTED);
781
782 /* disconnect line members */
783 list =
784 start_list = gtk_container_get_children(GTK_CONTAINER(effect_line->grid));
785
786 while(list != NULL){
787 if(AGS_IS_CONNECTABLE(list->data)){
788 ags_connectable_disconnect(AGS_CONNECTABLE(list->data));
789 }
790
791 list = list->next;
792 }
793
794 g_list_free(start_list);
795 }
796
797 /**
798 * ags_effect_line_plugin_alloc:
799 * @play_container: the #AgsRecallContainer
800 * @recall_container: the #AgsRecallContainer
801 * @plugin_name: the plugin name
802 * @filename: the filename as string
803 * @effect: the effect as string
804 *
805 * Allocate #AgsEffectLinePlugin-struct.
806 *
807 * Returns: the newly allocated #AgsEffectLinePlugin-struct
808 *
809 * Since: 3.3.0
810 */
811 AgsEffectLinePlugin*
ags_effect_line_plugin_alloc(AgsRecallContainer * play_container,AgsRecallContainer * recall_container,gchar * plugin_name,gchar * filename,gchar * effect)812 ags_effect_line_plugin_alloc(AgsRecallContainer *play_container, AgsRecallContainer *recall_container,
813 gchar *plugin_name,
814 gchar *filename,
815 gchar *effect)
816 {
817 AgsEffectLinePlugin *effect_line_plugin;
818
819 effect_line_plugin = (AgsEffectLinePlugin *) g_malloc(sizeof(AgsEffectLinePlugin));
820
821 if(play_container != NULL){
822 g_object_ref(play_container);
823 }
824
825 effect_line_plugin->play_container = play_container;
826
827 if(recall_container != NULL){
828 g_object_ref(recall_container);
829 }
830
831 effect_line_plugin->recall_container = recall_container;
832
833 effect_line_plugin->plugin_name = g_strdup(plugin_name);
834
835 effect_line_plugin->filename = g_strdup(filename);
836 effect_line_plugin->effect = g_strdup(effect);
837
838 effect_line_plugin->control_type_name = NULL;
839
840 effect_line_plugin->control_count = 0;
841
842 return(effect_line_plugin);
843 }
844
845 /**
846 * ags_effect_line_plugin_free:
847 * @effect_line_plugin: the #AgsEffectLinePlugin-struct
848 *
849 * Free @effect_line_plugin.
850 *
851 * Since: 3.3.0
852 */
853 void
ags_effect_line_plugin_free(AgsEffectLinePlugin * effect_line_plugin)854 ags_effect_line_plugin_free(AgsEffectLinePlugin *effect_line_plugin)
855 {
856 if(effect_line_plugin == NULL){
857 return;
858 }
859
860 if(effect_line_plugin->play_container != NULL){
861 g_object_unref(effect_line_plugin->play_container);
862 }
863
864 if(effect_line_plugin->recall_container != NULL){
865 g_object_unref(effect_line_plugin->recall_container);
866 }
867
868 if(effect_line_plugin->filename != NULL){
869 g_free(effect_line_plugin->filename);
870 }
871
872 if(effect_line_plugin->effect != NULL){
873 g_free(effect_line_plugin->effect);
874 }
875
876 if(effect_line_plugin->control_type_name != NULL){
877 g_list_free(effect_line_plugin->control_type_name);
878 }
879
880 g_free(effect_line_plugin);
881 }
882
883 /**
884 * ags_effect_line_samplerate_changed:
885 * @effect_line: the #AgsEffectLine
886 * @samplerate: the samplerate
887 * @old_samplerate: the old samplerate
888 *
889 * Notify about samplerate changed.
890 *
891 * Since: 3.0.0
892 */
893 void
ags_effect_line_samplerate_changed(AgsEffectLine * effect_line,guint samplerate,guint old_samplerate)894 ags_effect_line_samplerate_changed(AgsEffectLine *effect_line,
895 guint samplerate, guint old_samplerate)
896 {
897 g_return_if_fail(AGS_IS_EFFECT_LINE(effect_line));
898
899 g_object_ref((GObject *) effect_line);
900 g_signal_emit(G_OBJECT(effect_line),
901 effect_line_signals[SAMPLERATE_CHANGED], 0,
902 samplerate,
903 old_samplerate);
904 g_object_unref((GObject *) effect_line);
905 }
906
907 /**
908 * ags_effect_line_buffer_size_changed:
909 * @effect_line: the #AgsEffectLine
910 * @buffer_size: the buffer_size
911 * @old_buffer_size: the old buffer_size
912 *
913 * Notify about buffer_size changed.
914 *
915 * Since: 3.0.0
916 */
917 void
ags_effect_line_buffer_size_changed(AgsEffectLine * effect_line,guint buffer_size,guint old_buffer_size)918 ags_effect_line_buffer_size_changed(AgsEffectLine *effect_line,
919 guint buffer_size, guint old_buffer_size)
920 {
921 g_return_if_fail(AGS_IS_EFFECT_LINE(effect_line));
922
923 g_object_ref((GObject *) effect_line);
924 g_signal_emit(G_OBJECT(effect_line),
925 effect_line_signals[BUFFER_SIZE_CHANGED], 0,
926 buffer_size,
927 old_buffer_size);
928 g_object_unref((GObject *) effect_line);
929 }
930
931 /**
932 * ags_effect_line_format_changed:
933 * @effect_line: the #AgsEffectLine
934 * @format: the format
935 * @old_format: the old format
936 *
937 * Notify about format changed.
938 *
939 * Since: 3.0.0
940 */
941 void
ags_effect_line_format_changed(AgsEffectLine * effect_line,guint format,guint old_format)942 ags_effect_line_format_changed(AgsEffectLine *effect_line,
943 guint format, guint old_format)
944 {
945 g_return_if_fail(AGS_IS_EFFECT_LINE(effect_line));
946
947 g_object_ref((GObject *) effect_line);
948 g_signal_emit(G_OBJECT(effect_line),
949 effect_line_signals[FORMAT_CHANGED], 0,
950 format,
951 old_format);
952 g_object_unref((GObject *) effect_line);
953 }
954
955 void
ags_effect_line_real_set_channel(AgsEffectLine * effect_line,AgsChannel * channel)956 ags_effect_line_real_set_channel(AgsEffectLine *effect_line, AgsChannel *channel)
957 {
958 gchar *str;
959
960 if(effect_line->channel == channel){
961 return;
962 }
963
964 if(effect_line->channel != NULL){
965 g_object_unref(G_OBJECT(effect_line->channel));
966 }
967
968 if(channel != NULL){
969 g_object_ref(G_OBJECT(channel));
970 }
971
972 if(effect_line->channel != NULL){
973 effect_line->flags &= (~AGS_EFFECT_LINE_PREMAPPED_RECALL);
974 }
975
976 if(channel != NULL){
977 effect_line->samplerate = channel->samplerate;
978 effect_line->buffer_size = channel->buffer_size;
979 effect_line->format = channel->format;
980 }
981
982 effect_line->channel = channel;
983
984 if(channel != NULL){
985 guint audio_channel;
986
987 /* get audio channel */
988 g_object_get(channel,
989 "audio-channel", &audio_channel,
990 NULL);
991
992 /* set label */
993 str = g_strdup_printf("%s %d", i18n("channel"), audio_channel + 1);
994 gtk_label_set_label(effect_line->label,
995 str);
996
997 g_free(str);
998 }else{
999 str = g_strdup_printf("%s (null)", i18n("channel"));
1000 gtk_label_set_label(effect_line->label,
1001 str);
1002
1003 g_free(str);
1004 }
1005 }
1006
1007 /**
1008 * ags_effect_line_set_channel:
1009 * @effect_line: the #AgsEffectLine
1010 * @channel: the #AgsChannel to set
1011 *
1012 * Is emitted as channel gets modified.
1013 *
1014 * Since: 3.0.0
1015 */
1016 void
ags_effect_line_set_channel(AgsEffectLine * effect_line,AgsChannel * channel)1017 ags_effect_line_set_channel(AgsEffectLine *effect_line, AgsChannel *channel)
1018 {
1019 g_return_if_fail(AGS_IS_EFFECT_LINE(effect_line));
1020
1021 g_object_ref((GObject *) effect_line);
1022 g_signal_emit(G_OBJECT(effect_line),
1023 effect_line_signals[SET_CHANNEL], 0,
1024 channel);
1025 g_object_unref((GObject *) effect_line);
1026 }
1027
1028 void
ags_effect_line_add_ladspa_plugin(AgsEffectLine * effect_line,GList * control_type_name,AgsRecallContainer * play_container,AgsRecallContainer * recall_container,gchar * plugin_name,gchar * filename,gchar * effect,guint start_audio_channel,guint stop_audio_channel,guint start_pad,guint stop_pad,gint position,guint create_flags,guint recall_flags)1029 ags_effect_line_add_ladspa_plugin(AgsEffectLine *effect_line,
1030 GList *control_type_name,
1031 AgsRecallContainer *play_container, AgsRecallContainer *recall_container,
1032 gchar *plugin_name,
1033 gchar *filename,
1034 gchar *effect,
1035 guint start_audio_channel, guint stop_audio_channel,
1036 guint start_pad, guint stop_pad,
1037 gint position,
1038 guint create_flags, guint recall_flags)
1039 {
1040 AgsLineMember *line_member;
1041 AgsEffectSeparator *separator;
1042
1043 AgsEffectLinePlugin *effect_line_plugin;
1044
1045 AgsAudio *audio;
1046 AgsChannel *channel;
1047
1048 AgsLadspaPlugin *ladspa_plugin;
1049
1050 GList *start_recall;
1051 GList *start_list, *list;
1052 GList *start_plugin_port, *plugin_port;
1053
1054 guint audio_channel;
1055 guint pad;
1056 gdouble page, step;
1057 guint port_count;
1058 guint control_count;
1059
1060 guint x, y;
1061 guint k;
1062
1063 audio = NULL;
1064 channel = NULL;
1065
1066 audio_channel = 0;
1067
1068 pad = 0;
1069
1070 g_object_get(effect_line,
1071 "channel", &channel,
1072 NULL);
1073
1074 /* alloc effect_line plugin */
1075 effect_line_plugin = ags_effect_line_plugin_alloc(play_container, recall_container,
1076 plugin_name,
1077 filename,
1078 effect);
1079 effect_line_plugin->control_type_name = control_type_name;
1080
1081 effect_line->plugin = g_list_append(effect_line->plugin,
1082 effect_line_plugin);
1083
1084 g_object_get(channel,
1085 "audio", &audio,
1086 "audio-channel", &audio_channel,
1087 "pad", &pad,
1088 NULL);
1089
1090 /* load plugin */
1091 ladspa_plugin = ags_ladspa_manager_find_ladspa_plugin(ags_ladspa_manager_get_instance(),
1092 filename, effect);
1093
1094 /* ags-fx-ladspa */
1095 start_recall = ags_fx_factory_create(audio,
1096 effect_line_plugin->play_container, effect_line_plugin->recall_container,
1097 plugin_name,
1098 filename,
1099 effect,
1100 audio_channel, audio_channel + 1,
1101 pad, pad + 1,
1102 position,
1103 create_flags | (AGS_IS_OUTPUT(channel) ? AGS_FX_FACTORY_OUTPUT: AGS_FX_FACTORY_INPUT), recall_flags);
1104
1105 g_list_free_full(start_recall,
1106 (GDestroyNotify) g_object_unref);
1107
1108 /* retrieve position within table */
1109 x = 0;
1110 y = 0;
1111
1112 list =
1113 start_list = gtk_container_get_children(effect_line->grid);
1114
1115 while(list != NULL){
1116 guint top_attach;
1117
1118 gtk_container_child_get(GTK_CONTAINER(effect_line->grid),
1119 list->data,
1120 "top-attach", &top_attach,
1121 NULL);
1122
1123 if(y <= top_attach){
1124 y = top_attach + 1;
1125 }
1126
1127 list = list->next;
1128 }
1129
1130 g_list_free(start_list);
1131
1132 /* add separator */
1133 separator = ags_effect_separator_new();
1134
1135 separator->play_container = play_container;
1136 separator->recall_container = recall_container;
1137
1138 g_object_set(separator,
1139 "text", effect,
1140 "filename", filename,
1141 "effect", effect,
1142 NULL);
1143
1144 gtk_widget_set_valign(separator,
1145 GTK_ALIGN_FILL);
1146 gtk_widget_set_halign(separator,
1147 GTK_ALIGN_FILL);
1148
1149 gtk_grid_attach(effect_line->grid,
1150 (GtkWidget *) separator,
1151 0, y,
1152 AGS_EFFECT_LINE_COLUMNS_COUNT, 1);
1153 gtk_widget_show_all(GTK_WIDGET(separator));
1154
1155 y++;
1156
1157 /* load ports */
1158 g_object_get(ladspa_plugin,
1159 "plugin-port", &start_plugin_port,
1160 NULL);
1161
1162 plugin_port = start_plugin_port;
1163
1164 port_count = g_list_length(start_plugin_port);
1165
1166 control_count = 0;
1167
1168 k = 0;
1169
1170 while(plugin_port != NULL){
1171 if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_CONTROL)){
1172 GtkWidget *child_widget;
1173
1174 AgsLadspaConversion *ladspa_conversion;
1175
1176 GType widget_type;
1177
1178 gchar *plugin_name;
1179 gchar *control_port;
1180 gchar *port_name;
1181
1182 guint unique_id;
1183 guint scale_precision;
1184 gdouble step_count;
1185 gboolean disable_seemless;
1186 gboolean do_step_conversion;
1187
1188 GRecMutex *plugin_port_mutex;
1189
1190 control_count++;
1191
1192 disable_seemless = FALSE;
1193 do_step_conversion = FALSE;
1194
1195 if(x == AGS_EFFECT_LINE_COLUMNS_COUNT){
1196 x = 0;
1197 y++;
1198 }
1199
1200 if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_TOGGLED)){
1201 disable_seemless = TRUE;
1202
1203 if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_OUTPUT)){
1204 widget_type = AGS_TYPE_LED;
1205 }else{
1206 widget_type = GTK_TYPE_TOGGLE_BUTTON;
1207 }
1208 }else{
1209 if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_OUTPUT)){
1210 widget_type = AGS_TYPE_HINDICATOR;
1211 }else{
1212 widget_type = AGS_TYPE_DIAL;
1213 }
1214 }
1215
1216 if(control_type_name != NULL){
1217 widget_type = g_type_from_name(control_type_name->data);
1218
1219 control_type_name = control_type_name->next;
1220 }
1221
1222 scale_precision = AGS_DIAL_DEFAULT_PRECISION;
1223 step_count = AGS_LADSPA_CONVERSION_DEFAULT_STEP_COUNT;
1224
1225 if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_INTEGER)){
1226 guint scale_steps;
1227
1228 g_object_get(plugin_port->data,
1229 "scale-steps", &scale_steps,
1230 NULL);
1231
1232 step_count =
1233 scale_precision = (gdouble) scale_steps;
1234
1235 disable_seemless = TRUE;
1236 }
1237
1238 /* get plugin port mutex */
1239 plugin_port_mutex = AGS_PLUGIN_PORT_GET_OBJ_MUTEX(plugin_port->data);
1240
1241 /* get port name */
1242 g_rec_mutex_lock(plugin_port_mutex);
1243
1244 port_name = g_strdup(AGS_PLUGIN_PORT(plugin_port->data)->port_name);
1245
1246 g_rec_mutex_unlock(plugin_port_mutex);
1247
1248 /* add line member */
1249 g_object_get(ladspa_plugin,
1250 "unique-id", &unique_id,
1251 NULL);
1252
1253 plugin_name = g_strdup_printf("ladspa-%u",
1254 unique_id);
1255
1256 control_port = g_strdup_printf("%u/%u",
1257 k + 1,
1258 port_count);
1259
1260 line_member = (AgsLineMember *) g_object_new(AGS_TYPE_LINE_MEMBER,
1261 "widget-type", widget_type,
1262 "widget-label", AGS_PLUGIN_PORT(plugin_port->data)->port_name,
1263 "play-container", play_container,
1264 "recall-container", recall_container,
1265 "plugin-name", plugin_name,
1266 "filename", filename,
1267 "effect", effect,
1268 "specifier", AGS_PLUGIN_PORT(plugin_port->data)->port_name,
1269 "control-port", control_port,
1270 "scale-precision", scale_precision,
1271 "step-count", step_count,
1272 NULL);
1273 child_widget = ags_line_member_get_widget(line_member);
1274
1275 g_free(plugin_name);
1276 g_free(control_port);
1277 g_free(port_name);
1278
1279 /* ladspa conversion */
1280 ladspa_conversion = NULL;
1281
1282 if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_BOUNDED_BELOW)){
1283 if(ladspa_conversion == NULL ||
1284 !AGS_IS_LADSPA_CONVERSION(ladspa_conversion)){
1285 ladspa_conversion = ags_ladspa_conversion_new();
1286 }
1287
1288 ladspa_conversion->flags |= AGS_LADSPA_CONVERSION_BOUNDED_BELOW;
1289 }
1290
1291 if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_BOUNDED_ABOVE)){
1292 if(ladspa_conversion == NULL ||
1293 !AGS_IS_LADSPA_CONVERSION(ladspa_conversion)){
1294 ladspa_conversion = ags_ladspa_conversion_new();
1295 }
1296
1297 ladspa_conversion->flags |= AGS_LADSPA_CONVERSION_BOUNDED_ABOVE;
1298 }
1299 if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_SAMPLERATE)){
1300 if(ladspa_conversion == NULL ||
1301 !AGS_IS_LADSPA_CONVERSION(ladspa_conversion)){
1302 ladspa_conversion = ags_ladspa_conversion_new();
1303 }
1304
1305 ladspa_conversion->flags |= AGS_LADSPA_CONVERSION_SAMPLERATE;
1306 }
1307
1308 if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_LOGARITHMIC)){
1309 if(ladspa_conversion == NULL ||
1310 !AGS_IS_LADSPA_CONVERSION(ladspa_conversion)){
1311 ladspa_conversion = ags_ladspa_conversion_new();
1312 }
1313
1314 ladspa_conversion->flags |= AGS_LADSPA_CONVERSION_LOGARITHMIC;
1315
1316 do_step_conversion = TRUE;
1317 }
1318
1319 g_object_set(line_member,
1320 "conversion", ladspa_conversion,
1321 NULL);
1322
1323 /* child widget */
1324 if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_TOGGLED)){
1325 line_member->port_flags = AGS_LINE_MEMBER_PORT_BOOLEAN;
1326 }
1327
1328 if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_INTEGER)){
1329 line_member->port_flags = AGS_LINE_MEMBER_PORT_INTEGER;
1330 }
1331
1332 if(AGS_IS_DIAL(child_widget)){
1333 AgsDial *dial;
1334 GtkAdjustment *adjustment;
1335
1336 float lower_bound, upper_bound;
1337 float default_value;
1338 gdouble lower, upper;
1339 gdouble control_value;
1340
1341 dial = (AgsDial *) child_widget;
1342
1343 if(disable_seemless){
1344 dial->flags &= (~AGS_DIAL_SEEMLESS_MODE);
1345 }
1346
1347 /* add controls of ports and apply range */
1348 g_rec_mutex_lock(plugin_port_mutex);
1349
1350 lower_bound = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->lower_value);
1351 upper_bound = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->upper_value);
1352
1353 g_rec_mutex_unlock(plugin_port_mutex);
1354
1355 if(do_step_conversion){
1356 g_object_set(ladspa_conversion,
1357 "lower", lower_bound,
1358 "upper", upper_bound,
1359 NULL);
1360
1361 lower = 0.0;
1362 upper = AGS_LADSPA_CONVERSION_DEFAULT_STEP_COUNT - 1.0;
1363
1364 #if 0
1365 if(!disable_seemless){
1366 g_object_get(ladspa_conversion,
1367 "step-count", &step_count,
1368 NULL);
1369 }
1370 #endif
1371 }else{
1372 lower = lower_bound;
1373 upper = upper_bound;
1374 }
1375
1376 adjustment = (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 0.1, 0.1, 0.0);
1377 g_object_set(dial,
1378 "adjustment", adjustment,
1379 NULL);
1380
1381 if(upper >= 0.0 && lower >= 0.0){
1382 step = (upper - lower) / step_count;
1383 }else if(upper < 0.0 && lower < 0.0){
1384 step = -1.0 * (lower - upper) / step_count;
1385 }else{
1386 step = (upper - lower) / step_count;
1387 }
1388
1389 if(step_count > 8){
1390 if(upper >= 0.0 && lower >= 0.0){
1391 page = (upper - lower) / AGS_DIAL_DEFAULT_PRECISION;
1392 }else if(upper < 0.0 && lower < 0.0){
1393 page = -1.0 * (lower - upper) / AGS_DIAL_DEFAULT_PRECISION;
1394 }else{
1395 page = (upper - lower) / AGS_DIAL_DEFAULT_PRECISION;
1396 }
1397 }else{
1398 page = step;
1399 }
1400
1401 gtk_adjustment_set_step_increment(adjustment,
1402 step);
1403 gtk_adjustment_set_page_increment(adjustment,
1404 page);
1405 gtk_adjustment_set_lower(adjustment,
1406 lower);
1407 gtk_adjustment_set_upper(adjustment,
1408 upper);
1409
1410 /* get/set default value */
1411 g_rec_mutex_lock(plugin_port_mutex);
1412
1413 default_value = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->default_value);
1414
1415 g_rec_mutex_unlock(plugin_port_mutex);
1416
1417 control_value = default_value;
1418
1419 if(ladspa_conversion != NULL){
1420 control_value = ags_conversion_convert((AgsConversion *) ladspa_conversion,
1421 default_value,
1422 TRUE);
1423 }
1424
1425 gtk_adjustment_set_value(adjustment,
1426 control_value);
1427 }else if(GTK_IS_RANGE(child_widget)){
1428 GtkRange *range;
1429 GtkAdjustment *adjustment;
1430
1431 float lower_bound, upper_bound;
1432 gdouble lower, upper;
1433 float default_value;
1434 gdouble control_value;
1435
1436 range = (GtkRange *) child_widget;
1437
1438 /* add controls of ports and apply range */
1439 g_rec_mutex_lock(plugin_port_mutex);
1440
1441 lower_bound = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->lower_value);
1442 upper_bound = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->upper_value);
1443
1444 g_rec_mutex_unlock(plugin_port_mutex);
1445
1446 if(do_step_conversion){
1447 g_object_set(ladspa_conversion,
1448 "lower", lower_bound,
1449 "upper", upper_bound,
1450 NULL);
1451
1452 lower = 0.0;
1453 upper = AGS_LADSPA_CONVERSION_DEFAULT_STEP_COUNT - 1.0;
1454
1455 #if 0
1456 if(!disable_seemless){
1457 g_object_get(ladspa_conversion,
1458 "step-count", &step_count,
1459 NULL);
1460 }
1461 #endif
1462 }else{
1463 lower = lower_bound;
1464 upper = upper_bound;
1465 }
1466
1467 g_object_get(range,
1468 "adjustment", &adjustment,
1469 NULL);
1470
1471 if(upper >= 0.0 && lower >= 0.0){
1472 step = (upper - lower) / step_count;
1473 }else if(upper < 0.0 && lower < 0.0){
1474 step = -1.0 * (lower - upper) / step_count;
1475 }else{
1476 step = (upper - lower) / step_count;
1477 }
1478
1479 if(step_count > 8){
1480 if(upper >= 0.0 && lower >= 0.0){
1481 page = (upper - lower) / AGS_DIAL_DEFAULT_PRECISION;
1482 }else if(upper < 0.0 && lower < 0.0){
1483 page = -1.0 * (lower - upper) / AGS_DIAL_DEFAULT_PRECISION;
1484 }else{
1485 page = (upper - lower) / AGS_DIAL_DEFAULT_PRECISION;
1486 }
1487 }else{
1488 page = step;
1489 }
1490
1491 gtk_adjustment_set_step_increment(adjustment,
1492 step);
1493 gtk_adjustment_set_page_increment(adjustment,
1494 page);
1495 gtk_adjustment_set_lower(adjustment,
1496 lower);
1497 gtk_adjustment_set_upper(adjustment,
1498 upper);
1499
1500 /* get/set default value */
1501 g_rec_mutex_lock(plugin_port_mutex);
1502
1503 default_value = (float) g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->default_value);
1504
1505 g_rec_mutex_unlock(plugin_port_mutex);
1506
1507 control_value = default_value;
1508
1509 if(ladspa_conversion != NULL){
1510 control_value = ags_conversion_convert((AgsConversion *) ladspa_conversion,
1511 default_value,
1512 TRUE);
1513 }
1514
1515 gtk_adjustment_set_value(adjustment,
1516 control_value);
1517 }else if(GTK_IS_SPIN_BUTTON(child_widget)){
1518 GtkSpinButton *spin_button;
1519 GtkAdjustment *adjustment;
1520
1521 float lower_bound, upper_bound;
1522 gdouble lower, upper;
1523 float default_value;
1524 gdouble control_value;
1525
1526 spin_button = (GtkSpinButton *) child_widget;
1527
1528 /* add controls of ports and apply range */
1529 g_rec_mutex_lock(plugin_port_mutex);
1530
1531 lower_bound = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->lower_value);
1532 upper_bound = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->upper_value);
1533
1534 g_rec_mutex_unlock(plugin_port_mutex);
1535
1536 if(do_step_conversion){
1537 g_object_set(ladspa_conversion,
1538 "lower", lower_bound,
1539 "upper", upper_bound,
1540 NULL);
1541
1542 lower = 0.0;
1543 upper = AGS_LADSPA_CONVERSION_DEFAULT_STEP_COUNT - 1.0;
1544
1545 #if 0
1546 if(!disable_seemless){
1547 g_object_get(ladspa_conversion,
1548 "step-count", &step_count,
1549 NULL);
1550 }
1551 #endif
1552 }else{
1553 lower = lower_bound;
1554 upper = upper_bound;
1555 }
1556
1557 g_object_get(spin_button,
1558 "adjustment", &adjustment,
1559 NULL);
1560
1561 if(upper >= 0.0 && lower >= 0.0){
1562 step = (upper - lower) / step_count;
1563 }else if(upper < 0.0 && lower < 0.0){
1564 step = -1.0 * (lower - upper) / step_count;
1565 }else{
1566 step = (upper - lower) / step_count;
1567 }
1568
1569 if(step_count > 8){
1570 if(upper >= 0.0 && lower >= 0.0){
1571 page = (upper - lower) / AGS_DIAL_DEFAULT_PRECISION;
1572 }else if(upper < 0.0 && lower < 0.0){
1573 page = -1.0 * (lower - upper) / AGS_DIAL_DEFAULT_PRECISION;
1574 }else{
1575 page = (upper - lower) / AGS_DIAL_DEFAULT_PRECISION;
1576 }
1577 }else{
1578 page = step;
1579 }
1580
1581 gtk_adjustment_set_step_increment(adjustment,
1582 step);
1583 gtk_adjustment_set_page_increment(adjustment,
1584 page);
1585 gtk_adjustment_set_lower(adjustment,
1586 lower);
1587 gtk_adjustment_set_upper(adjustment,
1588 upper);
1589
1590 /* get/set default value */
1591 g_rec_mutex_lock(plugin_port_mutex);
1592
1593 default_value = (float) g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->default_value);
1594
1595 g_rec_mutex_unlock(plugin_port_mutex);
1596
1597 control_value = default_value;
1598
1599 if(ladspa_conversion != NULL){
1600 control_value = ags_conversion_convert((AgsConversion *) ladspa_conversion,
1601 default_value,
1602 TRUE);
1603 }
1604
1605 gtk_adjustment_set_value(adjustment,
1606 control_value);
1607 }else if(AGS_IS_INDICATOR(child_widget) ||
1608 AGS_IS_LED(child_widget)){
1609 g_hash_table_insert(ags_effect_line_indicator_queue_draw,
1610 child_widget, ags_effect_line_indicator_queue_draw_timeout);
1611
1612 effect_line->queued_drawing = g_list_prepend(effect_line->queued_drawing,
1613 child_widget);
1614
1615 g_timeout_add(AGS_UI_PROVIDER_DEFAULT_TIMEOUT * 1000.0,
1616 (GSourceFunc) ags_effect_line_indicator_queue_draw_timeout,
1617 (gpointer) child_widget);
1618 }
1619
1620 #ifdef AGS_DEBUG
1621 g_message("ladspa bounds: %f %f", lower, upper);
1622 #endif
1623
1624 gtk_widget_set_valign(line_member,
1625 GTK_ALIGN_FILL);
1626 gtk_widget_set_halign(line_member,
1627 GTK_ALIGN_FILL);
1628
1629 gtk_grid_attach(effect_line->grid,
1630 (GtkWidget *) line_member,
1631 (x % AGS_EFFECT_LINE_COLUMNS_COUNT), y,
1632 1, 1);
1633
1634 ags_connectable_connect(AGS_CONNECTABLE(line_member));
1635 gtk_widget_show_all((GtkWidget *) line_member);
1636
1637 /* iterate */
1638 x++;
1639
1640 if(x % AGS_EFFECT_LINE_COLUMNS_COUNT == 0){
1641 y++;
1642 }
1643 }
1644
1645 /* iterate */
1646 plugin_port = plugin_port->next;
1647 k++;
1648 }
1649
1650 effect_line_plugin->control_count = control_count;
1651
1652 if(audio != NULL){
1653 g_object_unref(audio);
1654 }
1655
1656 if(channel != NULL){
1657 g_object_unref(channel);
1658 }
1659
1660 g_list_free_full(start_plugin_port,
1661 g_object_unref);
1662 }
1663
1664 void
ags_effect_line_add_lv2_plugin(AgsEffectLine * effect_line,GList * control_type_name,AgsRecallContainer * play_container,AgsRecallContainer * recall_container,gchar * plugin_name,gchar * filename,gchar * effect,guint start_audio_channel,guint stop_audio_channel,guint start_pad,guint stop_pad,gint position,guint create_flags,guint recall_flags)1665 ags_effect_line_add_lv2_plugin(AgsEffectLine *effect_line,
1666 GList *control_type_name,
1667 AgsRecallContainer *play_container, AgsRecallContainer *recall_container,
1668 gchar *plugin_name,
1669 gchar *filename,
1670 gchar *effect,
1671 guint start_audio_channel, guint stop_audio_channel,
1672 guint start_pad, guint stop_pad,
1673 gint position,
1674 guint create_flags, guint recall_flags)
1675 {
1676 AgsLineMember *line_member;
1677 AgsEffectSeparator *separator;
1678
1679 AgsEffectLinePlugin *effect_line_plugin;
1680
1681 AgsAudio *audio;
1682 AgsChannel *channel;
1683
1684 AgsLv2Manager *lv2_manager;
1685 AgsLv2Plugin *lv2_plugin;
1686
1687 GList *start_recall;
1688 GList *start_list, *list;
1689 GList *start_plugin_port, *plugin_port;
1690
1691 gchar *uri;
1692
1693 gboolean is_lv2_plugin;
1694
1695 guint audio_channel;
1696 guint pad;
1697 gdouble page, step;
1698 guint port_count;
1699 guint control_count;
1700
1701 guint x, y;
1702 guint k;
1703
1704 GRecMutex *lv2_manager_mutex;
1705 GRecMutex *base_plugin_mutex;
1706
1707 lv2_manager = ags_lv2_manager_get_instance();
1708
1709 lv2_manager_mutex = AGS_LV2_MANAGER_GET_OBJ_MUTEX(lv2_manager);
1710
1711 audio = NULL;
1712 channel = NULL;
1713
1714 pad = 0;
1715 audio_channel = 0;
1716
1717 g_object_get(effect_line,
1718 "channel", &channel,
1719 NULL);
1720
1721 /* make sure turtle is parsed */
1722 g_rec_mutex_lock(lv2_manager_mutex);
1723
1724 is_lv2_plugin = ((lv2_manager->quick_scan_plugin_filename != NULL &&
1725 g_strv_contains(lv2_manager->quick_scan_plugin_filename,
1726 filename)) ||
1727 (lv2_manager->quick_scan_instrument_filename != NULL &&
1728 g_strv_contains(lv2_manager->quick_scan_instrument_filename,
1729 filename))) ? TRUE: FALSE;
1730
1731 g_rec_mutex_unlock(lv2_manager_mutex);
1732
1733 if(filename != NULL &&
1734 effect != NULL &&
1735 is_lv2_plugin){
1736 AgsTurtle *manifest;
1737 AgsTurtleManager *turtle_manager;
1738
1739 gchar *path;
1740 gchar *manifest_filename;
1741
1742 turtle_manager = ags_turtle_manager_get_instance();
1743
1744 path = g_path_get_dirname(filename);
1745
1746 manifest_filename = g_strdup_printf("%s%c%s",
1747 path,
1748 G_DIR_SEPARATOR,
1749 "manifest.ttl");
1750
1751 manifest = (AgsTurtle *) ags_turtle_manager_find(turtle_manager,
1752 manifest_filename);
1753
1754 if(manifest == NULL){
1755 AgsLv2TurtleParser *lv2_turtle_parser;
1756
1757 AgsTurtle **turtle;
1758
1759 guint n_turtle;
1760
1761 g_message("new turtle [Manifest] - %s", manifest_filename);
1762
1763 manifest = ags_turtle_new(manifest_filename);
1764 ags_turtle_load(manifest,
1765 NULL);
1766 ags_turtle_manager_add(turtle_manager,
1767 (GObject *) manifest);
1768
1769 lv2_turtle_parser = ags_lv2_turtle_parser_new(manifest);
1770
1771 n_turtle = 1;
1772 turtle = (AgsTurtle **) malloc(2 * sizeof(AgsTurtle *));
1773
1774 turtle[0] = manifest;
1775 turtle[1] = NULL;
1776
1777 ags_lv2_turtle_parser_parse(lv2_turtle_parser,
1778 turtle, n_turtle);
1779
1780 g_object_run_dispose((GObject *) lv2_turtle_parser);
1781 g_object_unref(lv2_turtle_parser);
1782
1783 g_object_unref(manifest);
1784
1785 free(turtle);
1786 }
1787
1788 g_free(manifest_filename);
1789 }
1790
1791 /* alloc effect line plugin */
1792 effect_line_plugin = ags_effect_line_plugin_alloc(play_container, recall_container,
1793 plugin_name,
1794 filename,
1795 effect);
1796 effect_line_plugin->control_type_name = control_type_name;
1797
1798 effect_line->plugin = g_list_append(effect_line->plugin,
1799 effect_line_plugin);
1800
1801 g_object_get(channel,
1802 "audio", &audio,
1803 "audio-channel", &audio_channel,
1804 "pad", &pad,
1805 NULL);
1806
1807 /* load plugin */
1808 lv2_plugin = ags_lv2_manager_find_lv2_plugin(ags_lv2_manager_get_instance(),
1809 filename, effect);
1810
1811 /* get base plugin mutex */
1812 base_plugin_mutex = AGS_BASE_PLUGIN_GET_OBJ_MUTEX(lv2_plugin);
1813
1814 /* get uri */
1815 g_rec_mutex_lock(base_plugin_mutex);
1816
1817 uri = g_strdup(lv2_plugin->uri);
1818
1819 g_rec_mutex_unlock(base_plugin_mutex);
1820
1821 /* ags-fx-lv2 */
1822 start_recall = ags_fx_factory_create(audio,
1823 effect_line_plugin->play_container, effect_line_plugin->recall_container,
1824 plugin_name,
1825 filename,
1826 effect,
1827 audio_channel, audio_channel + 1,
1828 pad, pad + 1,
1829 position,
1830 create_flags | (AGS_IS_OUTPUT(channel) ? AGS_FX_FACTORY_OUTPUT: AGS_FX_FACTORY_INPUT), recall_flags);
1831
1832 g_list_free_full(start_recall,
1833 (GDestroyNotify) g_object_unref);
1834
1835 /* retrieve position within table */
1836 x = 0;
1837 y = 0;
1838
1839 list =
1840 start_list = gtk_container_get_children(effect_line->grid);
1841
1842 while(list != NULL){
1843 guint top_attach;
1844
1845 gtk_container_child_get(GTK_CONTAINER(effect_line->grid),
1846 list->data,
1847 "top-attach", &top_attach,
1848 NULL);
1849
1850 if(y <= top_attach){
1851 y = top_attach + 1;
1852 }
1853
1854 list = list->next;
1855 }
1856
1857 g_list_free(start_list);
1858
1859 /* add separator */
1860 separator = ags_effect_separator_new();
1861
1862 separator->play_container = play_container;
1863 separator->recall_container = recall_container;
1864
1865 g_object_set(separator,
1866 "text", effect,
1867 "filename", filename,
1868 "effect", effect,
1869 NULL);
1870
1871 gtk_widget_set_valign(separator,
1872 GTK_ALIGN_FILL);
1873 gtk_widget_set_halign(separator,
1874 GTK_ALIGN_FILL);
1875
1876 gtk_grid_attach(effect_line->grid,
1877 (GtkWidget *) separator,
1878 0, y,
1879 AGS_EFFECT_LINE_COLUMNS_COUNT, 1);
1880 gtk_widget_show_all(GTK_WIDGET(separator));
1881
1882 y++;
1883
1884 /* load ports */
1885 g_object_get(lv2_plugin,
1886 "plugin-port", &start_plugin_port,
1887 NULL);
1888
1889 plugin_port = start_plugin_port;
1890
1891 port_count = g_list_length(start_plugin_port);
1892
1893 control_count = 0;
1894
1895 k = 0;
1896
1897 while(plugin_port != NULL){
1898 if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_CONTROL)){
1899 GtkWidget *child_widget;
1900
1901 AgsLv2Conversion *lv2_conversion;
1902
1903 GType widget_type;
1904
1905 gchar *plugin_name;
1906 gchar *control_port;
1907 gchar *port_name;
1908
1909 guint scale_precision;
1910 gdouble step_count;
1911 gboolean disable_seemless;
1912 gboolean do_step_conversion;
1913
1914 GRecMutex *plugin_port_mutex;
1915
1916 control_count++;
1917
1918 disable_seemless = FALSE;
1919 do_step_conversion = FALSE;
1920
1921 if(x == AGS_EFFECT_LINE_COLUMNS_COUNT){
1922 x = 0;
1923 y++;
1924 }
1925
1926 if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_TOGGLED)){
1927 disable_seemless = TRUE;
1928
1929 if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_OUTPUT)){
1930 widget_type = AGS_TYPE_LED;
1931 }else{
1932 widget_type = GTK_TYPE_TOGGLE_BUTTON;
1933 }
1934 }else{
1935 if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_OUTPUT)){
1936 widget_type = AGS_TYPE_HINDICATOR;
1937 }else{
1938 widget_type = AGS_TYPE_DIAL;
1939 }
1940 }
1941
1942 if(control_type_name != NULL){
1943 widget_type = g_type_from_name(control_type_name->data);
1944
1945 control_type_name = control_type_name->next;
1946 }
1947
1948 scale_precision = AGS_DIAL_DEFAULT_PRECISION;
1949 step_count = AGS_LV2_CONVERSION_DEFAULT_STEP_COUNT;
1950
1951 if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_INTEGER)){
1952 guint scale_steps;
1953
1954 g_object_get(plugin_port->data,
1955 "scale-steps", &scale_steps,
1956 NULL);
1957
1958 step_count =
1959 scale_precision = (gdouble) scale_steps;
1960
1961 disable_seemless = TRUE;
1962 }
1963
1964 /* get plugin port mutex */
1965 plugin_port_mutex = AGS_PLUGIN_PORT_GET_OBJ_MUTEX(plugin_port->data);
1966
1967 /* get port name */
1968 g_rec_mutex_lock(plugin_port_mutex);
1969
1970 port_name = g_strdup(AGS_PLUGIN_PORT(plugin_port->data)->port_name);
1971
1972 g_rec_mutex_unlock(plugin_port_mutex);
1973
1974 /* add line member */
1975 plugin_name = g_strdup_printf("lv2-<%s>",
1976 uri);
1977
1978 control_port = g_strdup_printf("%u/%u",
1979 k + 1,
1980 port_count);
1981
1982 line_member = (AgsLineMember *) g_object_new(AGS_TYPE_LINE_MEMBER,
1983 "widget-type", widget_type,
1984 "widget-label", port_name,
1985 "plugin-name", plugin_name,
1986 "filename", filename,
1987 "effect", effect,
1988 "specifier", port_name,
1989 "control-port", control_port,
1990 "scale-precision", scale_precision,
1991 "step-count", step_count,
1992 NULL);
1993 child_widget = ags_line_member_get_widget(line_member);
1994
1995 g_free(plugin_name);
1996 g_free(control_port);
1997 g_free(port_name);
1998
1999 /* lv2 conversion */
2000 lv2_conversion = NULL;
2001
2002 if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_LOGARITHMIC)){
2003 if(lv2_conversion == NULL ||
2004 !AGS_IS_LV2_CONVERSION(lv2_conversion)){
2005 lv2_conversion = ags_lv2_conversion_new();
2006 }
2007
2008 lv2_conversion->flags |= AGS_LV2_CONVERSION_LOGARITHMIC;
2009
2010 do_step_conversion = TRUE;
2011 }
2012
2013 g_object_set(line_member,
2014 "conversion", lv2_conversion,
2015 NULL);
2016
2017 /* child widget */
2018 if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_TOGGLED)){
2019 line_member->port_flags = AGS_LINE_MEMBER_PORT_BOOLEAN;
2020 }
2021
2022 if(ags_plugin_port_test_flags(plugin_port->data, AGS_PLUGIN_PORT_INTEGER)){
2023 line_member->port_flags = AGS_LINE_MEMBER_PORT_INTEGER;
2024 }
2025
2026 if(AGS_IS_DIAL(child_widget)){
2027 AgsDial *dial;
2028 GtkAdjustment *adjustment;
2029
2030 float lower_bound, upper_bound;
2031 gdouble lower, upper;
2032 float default_value;
2033 gdouble control_value;
2034
2035 dial = (AgsDial *) child_widget;
2036
2037 if(disable_seemless){
2038 dial->flags &= (~AGS_DIAL_SEEMLESS_MODE);
2039 }
2040
2041 /* add controls of ports and apply range */
2042 g_rec_mutex_lock(plugin_port_mutex);
2043
2044 lower_bound = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->lower_value);
2045 upper_bound = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->upper_value);
2046
2047 g_rec_mutex_unlock(plugin_port_mutex);
2048
2049 if(do_step_conversion){
2050 g_object_set(lv2_conversion,
2051 "lower", lower_bound,
2052 "upper", upper_bound,
2053 NULL);
2054
2055 lower = 0.0;
2056 upper = AGS_LV2_CONVERSION_DEFAULT_STEP_COUNT - 1.0;
2057
2058 #if 0
2059 if(!disable_seemless){
2060 g_object_get(lv2_conversion,
2061 "step-count", &step_count,
2062 NULL);
2063 }
2064 #endif
2065 }else{
2066 lower = lower_bound;
2067 upper = upper_bound;
2068 }
2069
2070 adjustment = (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 0.1, 0.1, 0.0);
2071 g_object_set(dial,
2072 "adjustment", adjustment,
2073 NULL);
2074
2075 if(upper >= 0.0 && lower >= 0.0){
2076 step = (upper - lower) / step_count;
2077 }else if(upper < 0.0 && lower < 0.0){
2078 step = -1.0 * (lower - upper) / step_count;
2079 }else{
2080 step = (upper - lower) / step_count;
2081 }
2082
2083 if(step_count > 8){
2084 if(upper >= 0.0 && lower >= 0.0){
2085 page = (upper - lower) / AGS_DIAL_DEFAULT_PRECISION;
2086 }else if(upper < 0.0 && lower < 0.0){
2087 page = -1.0 * (lower - upper) / AGS_DIAL_DEFAULT_PRECISION;
2088 }else{
2089 page = (upper - lower) / AGS_DIAL_DEFAULT_PRECISION;
2090 }
2091 }else{
2092 page = step;
2093 }
2094
2095 gtk_adjustment_set_step_increment(adjustment,
2096 step);
2097 gtk_adjustment_set_page_increment(adjustment,
2098 page);
2099 gtk_adjustment_set_lower(adjustment,
2100 lower);
2101 gtk_adjustment_set_upper(adjustment,
2102 upper);
2103
2104 /* get/set default value */
2105 g_rec_mutex_lock(plugin_port_mutex);
2106
2107 default_value = (float) g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->default_value);
2108
2109 g_rec_mutex_unlock(plugin_port_mutex);
2110
2111 control_value = default_value;
2112
2113 if(lv2_conversion != NULL){
2114 control_value = ags_conversion_convert((AgsConversion *) lv2_conversion,
2115 default_value,
2116 TRUE);
2117 }
2118
2119 gtk_adjustment_set_value(adjustment,
2120 control_value);
2121 }else if(GTK_IS_RANGE(child_widget)){
2122 GtkRange *range;
2123 GtkAdjustment *adjustment;
2124
2125 float lower_bound, upper_bound;
2126 gdouble lower, upper;
2127 float default_value;
2128 gdouble control_value;
2129
2130 range = (GtkRange *) child_widget;
2131
2132 /* add controls of ports and apply range */
2133 g_rec_mutex_lock(plugin_port_mutex);
2134
2135 lower_bound = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->lower_value);
2136 upper_bound = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->upper_value);
2137
2138 g_rec_mutex_unlock(plugin_port_mutex);
2139
2140 if(do_step_conversion){
2141 g_object_set(lv2_conversion,
2142 "lower", lower_bound,
2143 "upper", upper_bound,
2144 NULL);
2145
2146 lower = 0.0;
2147 upper = AGS_LV2_CONVERSION_DEFAULT_STEP_COUNT - 1.0;
2148
2149 #if 0
2150 if(!disable_seemless){
2151 g_object_get(lv2_conversion,
2152 "step-count", &step_count,
2153 NULL);
2154 }
2155 #endif
2156 }else{
2157 lower = lower_bound;
2158 upper = upper_bound;
2159 }
2160
2161 g_object_get(range,
2162 "adjustment", &adjustment,
2163 NULL);
2164
2165 if(upper >= 0.0 && lower >= 0.0){
2166 step = (upper - lower) / step_count;
2167 }else if(upper < 0.0 && lower < 0.0){
2168 step = -1.0 * (lower - upper) / step_count;
2169 }else{
2170 step = (upper - lower) / step_count;
2171 }
2172
2173 if(step_count > 8){
2174 if(upper >= 0.0 && lower >= 0.0){
2175 page = (upper - lower) / AGS_DIAL_DEFAULT_PRECISION;
2176 }else if(upper < 0.0 && lower < 0.0){
2177 page = -1.0 * (lower - upper) / AGS_DIAL_DEFAULT_PRECISION;
2178 }else{
2179 page = (upper - lower) / AGS_DIAL_DEFAULT_PRECISION;
2180 }
2181 }else{
2182 page = step;
2183 }
2184
2185 gtk_adjustment_set_step_increment(adjustment,
2186 step);
2187 gtk_adjustment_set_page_increment(adjustment,
2188 page);
2189 gtk_adjustment_set_lower(adjustment,
2190 lower);
2191 gtk_adjustment_set_upper(adjustment,
2192 upper);
2193
2194 /* get/set default value */
2195 g_rec_mutex_lock(plugin_port_mutex);
2196
2197 default_value = (float) g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->default_value);
2198
2199 g_rec_mutex_unlock(plugin_port_mutex);
2200
2201 control_value = default_value;
2202
2203 if(lv2_conversion != NULL){
2204 control_value = ags_conversion_convert((AgsConversion *) lv2_conversion,
2205 default_value,
2206 TRUE);
2207 }
2208
2209 gtk_adjustment_set_value(adjustment,
2210 control_value);
2211 }else if(GTK_IS_SPIN_BUTTON(child_widget)){
2212 GtkSpinButton *spin_button;
2213 GtkAdjustment *adjustment;
2214
2215 float lower_bound, upper_bound;
2216 gdouble lower, upper;
2217 float default_value;
2218 gdouble control_value;
2219
2220 spin_button = (GtkSpinButton *) child_widget;
2221
2222 /* add controls of ports and apply range */
2223 g_rec_mutex_lock(plugin_port_mutex);
2224
2225 lower_bound = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->lower_value);
2226 upper_bound = g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->upper_value);
2227
2228 g_rec_mutex_unlock(plugin_port_mutex);
2229
2230 if(do_step_conversion){
2231 g_object_set(lv2_conversion,
2232 "lower", lower_bound,
2233 "upper", upper_bound,
2234 NULL);
2235
2236 lower = 0.0;
2237 upper = AGS_LV2_CONVERSION_DEFAULT_STEP_COUNT - 1.0;
2238
2239 #if 0
2240 if(!disable_seemless){
2241 g_object_get(lv2_conversion,
2242 "step-count", &step_count,
2243 NULL);
2244 }
2245 #endif
2246 }else{
2247 lower = lower_bound;
2248 upper = upper_bound;
2249 }
2250
2251 g_object_get(spin_button,
2252 "adjustment", &adjustment,
2253 NULL);
2254
2255 if(upper >= 0.0 && lower >= 0.0){
2256 step = (upper - lower) / step_count;
2257 }else if(upper < 0.0 && lower < 0.0){
2258 step = -1.0 * (lower - upper) / step_count;
2259 }else{
2260 step = (upper - lower) / step_count;
2261 }
2262
2263 if(step_count > 8){
2264 if(upper >= 0.0 && lower >= 0.0){
2265 page = (upper - lower) / AGS_DIAL_DEFAULT_PRECISION;
2266 }else if(upper < 0.0 && lower < 0.0){
2267 page = -1.0 * (lower - upper) / AGS_DIAL_DEFAULT_PRECISION;
2268 }else{
2269 page = (upper - lower) / AGS_DIAL_DEFAULT_PRECISION;
2270 }
2271 }else{
2272 page = step;
2273 }
2274
2275 gtk_adjustment_set_step_increment(adjustment,
2276 step);
2277 gtk_adjustment_set_page_increment(adjustment,
2278 page);
2279 gtk_adjustment_set_lower(adjustment,
2280 lower);
2281 gtk_adjustment_set_upper(adjustment,
2282 upper);
2283
2284 /* get/set default value */
2285 g_rec_mutex_lock(plugin_port_mutex);
2286
2287 default_value = (float) g_value_get_float(AGS_PLUGIN_PORT(plugin_port->data)->default_value);
2288
2289 g_rec_mutex_unlock(plugin_port_mutex);
2290
2291 control_value = default_value;
2292
2293 if(lv2_conversion != NULL){
2294 control_value = ags_conversion_convert((AgsConversion *) lv2_conversion,
2295 default_value,
2296 TRUE);
2297 }
2298
2299 gtk_adjustment_set_value(adjustment,
2300 control_value);
2301 }else if(AGS_IS_INDICATOR(child_widget) ||
2302 AGS_IS_LED(child_widget)){
2303 g_hash_table_insert(ags_effect_line_indicator_queue_draw,
2304 child_widget,
2305 ags_effect_line_indicator_queue_draw_timeout);
2306
2307 effect_line->queued_drawing = g_list_prepend(effect_line->queued_drawing,
2308 child_widget);
2309
2310 g_timeout_add(AGS_UI_PROVIDER_DEFAULT_TIMEOUT * 1000.0,
2311 (GSourceFunc) ags_effect_line_indicator_queue_draw_timeout,
2312 (gpointer) child_widget);
2313 }
2314
2315 #ifdef AGS_DEBUG
2316 g_message("lv2 bounds: %f %f", lower, upper);
2317 #endif
2318
2319 gtk_widget_set_valign(line_member,
2320 GTK_ALIGN_FILL);
2321 gtk_widget_set_halign(line_member,
2322 GTK_ALIGN_FILL);
2323
2324 gtk_grid_attach(effect_line->grid,
2325 (GtkWidget *) line_member,
2326 (x % AGS_EFFECT_LINE_COLUMNS_COUNT), y,
2327 1, 1);
2328
2329 ags_connectable_connect(AGS_CONNECTABLE(line_member));
2330 gtk_widget_show_all((GtkWidget *) line_member);
2331
2332 /* iterate */
2333 x++;
2334
2335 if(x % AGS_EFFECT_LINE_COLUMNS_COUNT == 0){
2336 y++;
2337 }
2338 }
2339
2340 /* iterate */
2341 plugin_port = plugin_port->next;
2342 k++;
2343 }
2344
2345 effect_line_plugin->control_count = control_count;
2346
2347 if(audio != NULL){
2348 g_object_unref(audio);
2349 }
2350
2351 if(channel != NULL){
2352 g_object_unref(channel);
2353 }
2354
2355 g_list_free_full(start_plugin_port,
2356 g_object_unref);
2357
2358 g_free(uri);
2359 }
2360
2361 void
ags_effect_line_real_add_plugin(AgsEffectLine * effect_line,GList * control_type_name,AgsRecallContainer * play_container,AgsRecallContainer * recall_container,gchar * plugin_name,gchar * filename,gchar * effect,guint start_audio_channel,guint stop_audio_channel,guint start_pad,guint stop_pad,gint position,guint create_flags,guint recall_flags)2362 ags_effect_line_real_add_plugin(AgsEffectLine *effect_line,
2363 GList *control_type_name,
2364 AgsRecallContainer *play_container, AgsRecallContainer *recall_container,
2365 gchar *plugin_name,
2366 gchar *filename,
2367 gchar *effect,
2368 guint start_audio_channel, guint stop_audio_channel,
2369 guint start_pad, guint stop_pad,
2370 gint position,
2371 guint create_flags, guint recall_flags)
2372 {
2373 AgsBasePlugin *base_plugin;
2374
2375 gchar *fallback_filename;
2376
2377 base_plugin = NULL;
2378
2379 fallback_filename = NULL;
2380
2381 if(!g_ascii_strncasecmp(plugin_name,
2382 "ags-fx-ladspa",
2383 14)){
2384 base_plugin = (AgsBasePlugin *) ags_ladspa_manager_find_ladspa_plugin_with_fallback(ags_ladspa_manager_get_instance(),
2385 filename, effect);
2386 }else if(!g_ascii_strncasecmp(plugin_name,
2387 "ags-fx-lv2",
2388 11)){
2389 base_plugin = (AgsBasePlugin *) ags_lv2_manager_find_lv2_plugin_with_fallback(ags_lv2_manager_get_instance(),
2390 filename, effect);
2391 }
2392
2393 if(base_plugin != NULL){
2394 g_object_get(base_plugin,
2395 "filename", &fallback_filename,
2396 NULL);
2397 }else{
2398 fallback_filename = g_strdup(filename);
2399 }
2400
2401 if((AGS_FX_FACTORY_ADD & (create_flags)) != 0){
2402 if(!g_ascii_strncasecmp(plugin_name,
2403 "ags-fx-ladspa",
2404 14)){
2405 ags_effect_line_add_ladspa_plugin(effect_line,
2406 control_type_name,
2407 play_container, recall_container,
2408 plugin_name,
2409 fallback_filename,
2410 effect,
2411 start_audio_channel, stop_audio_channel,
2412 start_pad, stop_pad,
2413 position,
2414 create_flags, recall_flags);
2415 }else if(!g_ascii_strncasecmp(plugin_name,
2416 "ags-fx-lv2",
2417 11)){
2418 ags_effect_line_add_lv2_plugin(effect_line,
2419 control_type_name,
2420 play_container, recall_container,
2421 plugin_name,
2422 fallback_filename,
2423 effect,
2424 start_audio_channel, stop_audio_channel,
2425 start_pad, stop_pad,
2426 position,
2427 create_flags, recall_flags);
2428 }
2429 }
2430
2431 g_free(fallback_filename);
2432 }
2433
2434 /**
2435 * ags_effect_line_add_plugin:
2436 * @effect_line: the #AgsEffectLine to modify
2437 * @control_type_name: the #GList-struct containing string representation of a #GType
2438 * @play_container: an #AgsRecallContainer to indetify what recall to use
2439 * @recall_container: an #AgsRecallContainer to indetify what recall to use
2440 * @plugin_name: the plugin identifier
2441 * @filename: the effect's filename
2442 * @effect: the effect's name
2443 * @start_audio_channel: the first audio channel to apply
2444 * @stop_audio_channel: the last audio channel to apply
2445 * @start_pad: the first pad to apply
2446 * @stop_pad: the last pad to apply
2447 * @position: the position to insert the recall
2448 * @create_flags: modify the behaviour of this function
2449 * @recall_flags: flags to be set for #AgsRecall
2450 *
2451 * Add an effect by its filename and effect specifier.
2452 *
2453 * Since: 3.3.0
2454 */
2455 void
ags_effect_line_add_plugin(AgsEffectLine * effect_line,GList * control_type_name,AgsRecallContainer * play_container,AgsRecallContainer * recall_container,gchar * plugin_name,gchar * filename,gchar * effect,guint start_audio_channel,guint stop_audio_channel,guint start_pad,guint stop_pad,gint position,guint create_flags,guint recall_flags)2456 ags_effect_line_add_plugin(AgsEffectLine *effect_line,
2457 GList *control_type_name,
2458 AgsRecallContainer *play_container, AgsRecallContainer *recall_container,
2459 gchar *plugin_name,
2460 gchar *filename,
2461 gchar *effect,
2462 guint start_audio_channel, guint stop_audio_channel,
2463 guint start_pad, guint stop_pad,
2464 gint position,
2465 guint create_flags, guint recall_flags)
2466 {
2467 g_return_if_fail(AGS_IS_EFFECT_LINE(effect_line));
2468
2469 g_object_ref((GObject *) effect_line);
2470 g_signal_emit(G_OBJECT(effect_line),
2471 effect_line_signals[ADD_PLUGIN], 0,
2472 control_type_name,
2473 play_container, recall_container,
2474 plugin_name,
2475 filename,
2476 effect,
2477 start_audio_channel, stop_audio_channel,
2478 start_pad, stop_pad,
2479 position,
2480 create_flags, recall_flags);
2481 g_object_unref((GObject *) effect_line);
2482 }
2483
2484 void
ags_effect_line_real_remove_plugin(AgsEffectLine * effect_line,guint nth)2485 ags_effect_line_real_remove_plugin(AgsEffectLine *effect_line,
2486 guint nth)
2487 {
2488 AgsEffectLinePlugin *effect_line_plugin;
2489
2490 AgsAudio *audio;
2491
2492 GList *start_list, *list;
2493 GList *start_recall, *recall;
2494
2495 if(!AGS_IS_EFFECT_LINE(effect_line)){
2496 return;
2497 }
2498
2499 audio = NULL;
2500
2501 list = g_list_nth(effect_line->plugin,
2502 nth);
2503
2504 if(list == NULL){
2505 return;
2506 }
2507
2508 effect_line_plugin = list->data;
2509
2510 g_object_get(effect_line->channel,
2511 "audio", &audio,
2512 NULL);
2513
2514 /* */
2515 effect_line->plugin = g_list_remove(effect_line->plugin,
2516 effect_line_plugin);
2517
2518 /* AgsRecallAudio */
2519 ags_audio_remove_recall(audio, (GObject *) ags_recall_container_get_recall_audio(effect_line_plugin->play_container),
2520 TRUE);
2521
2522 ags_audio_remove_recall(audio, (GObject *) ags_recall_container_get_recall_audio(effect_line_plugin->recall_container),
2523 FALSE);
2524
2525 /* AgsRecallAudioRun - play context */
2526 g_object_get(effect_line_plugin->play_container,
2527 "recall-audio-run", &start_recall,
2528 NULL);
2529
2530 recall = start_recall;
2531
2532 while(recall != NULL){
2533 ags_audio_remove_recall(audio, recall->data,
2534 TRUE);
2535
2536 recall = recall->next;
2537 }
2538
2539 g_list_free_full(start_recall,
2540 (GDestroyNotify) g_object_unref);
2541
2542 /* AgsRecallAudioRun - recall context */
2543 g_object_get(effect_line_plugin->recall_container,
2544 "recall-audio-run", &start_recall,
2545 NULL);
2546
2547 recall = start_recall;
2548
2549 while(recall != NULL){
2550 ags_audio_remove_recall(audio, (GObject *) recall->data,
2551 FALSE);
2552
2553 recall = recall->next;
2554 }
2555
2556 g_list_free_full(start_recall,
2557 (GDestroyNotify) g_object_unref);
2558
2559 /* AgsRecallChannel - play context */
2560 g_object_get(effect_line_plugin->play_container,
2561 "recall-channel", &start_recall,
2562 NULL);
2563
2564 recall = start_recall;
2565
2566 while(recall != NULL){
2567 AgsChannel *channel;
2568
2569 g_object_get(recall->data,
2570 "source", &channel,
2571 NULL);
2572
2573 ags_channel_remove_recall(channel, (GObject *) recall->data,
2574 TRUE);
2575
2576 if(channel != NULL){
2577 g_object_unref(channel);
2578 }
2579
2580 recall = recall->next;
2581 }
2582
2583 g_list_free_full(start_recall,
2584 (GDestroyNotify) g_object_unref);
2585
2586 /* AgsRecallChannel - recall context */
2587 g_object_get(effect_line_plugin->recall_container,
2588 "recall-channel", &start_recall,
2589 NULL);
2590
2591 recall = start_recall;
2592
2593 while(recall != NULL){
2594 AgsChannel *channel;
2595
2596 g_object_get(recall->data,
2597 "source", &channel,
2598 NULL);
2599
2600 ags_channel_remove_recall(channel, (GObject *) recall->data,
2601 FALSE);
2602
2603
2604 if(channel != NULL){
2605 g_object_unref(channel);
2606 }
2607
2608 recall = recall->next;
2609 }
2610
2611 g_list_free_full(start_recall,
2612 (GDestroyNotify) g_object_unref);
2613
2614 /* AgsRecallChannelRun - play context */
2615 g_object_get(effect_line_plugin->play_container,
2616 "recall-channel-run", &start_recall,
2617 NULL);
2618
2619 recall = start_recall;
2620
2621 while(recall != NULL){
2622 AgsChannel *channel;
2623
2624 g_object_get(recall->data,
2625 "source", &channel,
2626 NULL);
2627
2628 ags_channel_remove_recall(channel, (GObject *) recall->data,
2629 TRUE);
2630
2631 if(channel != NULL){
2632 g_object_unref(channel);
2633 }
2634
2635 recall = recall->next;
2636 }
2637
2638 g_list_free_full(start_recall,
2639 (GDestroyNotify) g_object_unref);
2640
2641 /* AgsRecallChannelRun - recall context */
2642 g_object_get(effect_line_plugin->recall_container,
2643 "recall-channel-run", &start_recall,
2644 NULL);
2645
2646 recall = start_recall;
2647
2648 while(recall != NULL){
2649 AgsChannel *channel;
2650
2651 g_object_get(recall->data,
2652 "source", &channel,
2653 NULL);
2654
2655 ags_channel_remove_recall(channel, (GObject *) recall->data,
2656 FALSE);
2657
2658 if(channel != NULL){
2659 g_object_unref(channel);
2660 }
2661
2662 recall = recall->next;
2663 }
2664
2665 g_list_free_full(start_recall,
2666 (GDestroyNotify) g_object_unref);
2667
2668 /* recall container */
2669 ags_audio_remove_recall_container(audio, (GObject *) effect_line_plugin->play_container);
2670 ags_audio_remove_recall_container(audio, (GObject *) effect_line_plugin->recall_container);
2671
2672 ags_channel_remove_recall_container(effect_line->channel, (GObject *) effect_line_plugin->play_container);
2673 ags_channel_remove_recall_container(effect_line->channel, (GObject *) effect_line_plugin->recall_container);
2674
2675 /* destroy controls - expander table */
2676 start_list = gtk_container_get_children((GtkContainer *) effect_line->grid);
2677
2678 list = start_list;
2679
2680 while(list != NULL){
2681 if(AGS_IS_LINE_MEMBER(list->data) &&
2682 AGS_LINE_MEMBER(list->data)->play_container == effect_line_plugin->play_container){
2683 if(AGS_IS_INDICATOR(list->data) ||
2684 AGS_IS_LED(list->data)){
2685 g_hash_table_remove(ags_effect_line_indicator_queue_draw,
2686 list->data);
2687 }
2688
2689 gtk_widget_destroy(list->data);
2690 }else if(AGS_IS_EFFECT_SEPARATOR(list->data) &&
2691 AGS_EFFECT_SEPARATOR(list->data)->play_container == effect_line_plugin->play_container){
2692 gtk_widget_destroy(list->data);
2693 }
2694
2695 list = list->next;
2696 }
2697
2698 g_list_free(start_list);
2699
2700 /* unref */
2701 if(audio != NULL){
2702 g_object_unref(audio);
2703 }
2704
2705 /* free AgsEffectLinePlugin */
2706 ags_effect_line_plugin_free(effect_line_plugin);
2707 }
2708
2709 /**
2710 * ags_effect_line_remove_plugin:
2711 * @effect_line: the #AgsEffectLine to modify
2712 * @nth: the nth effect to remove
2713 *
2714 * Remove an effect by its position.
2715 *
2716 * Since: 3.3.0
2717 */
2718 void
ags_effect_line_remove_plugin(AgsEffectLine * effect_line,guint nth)2719 ags_effect_line_remove_plugin(AgsEffectLine *effect_line,
2720 guint nth)
2721 {
2722 g_return_if_fail(AGS_IS_EFFECT_LINE(effect_line));
2723
2724 g_object_ref((GObject *) effect_line);
2725 g_signal_emit(G_OBJECT(effect_line),
2726 effect_line_signals[REMOVE_PLUGIN], 0,
2727 nth);
2728 g_object_unref((GObject *) effect_line);
2729 }
2730
2731 void
ags_effect_line_real_map_recall(AgsEffectLine * effect_line,guint ouput_pad_start)2732 ags_effect_line_real_map_recall(AgsEffectLine *effect_line,
2733 guint ouput_pad_start)
2734 {
2735 if((AGS_EFFECT_LINE_MAPPED_RECALL & (effect_line->flags)) != 0){
2736 return;
2737 }
2738
2739 effect_line->flags |= AGS_EFFECT_LINE_MAPPED_RECALL;
2740
2741 ags_effect_line_find_port(effect_line);
2742 }
2743
2744 /**
2745 * ags_effect_line_map_recall:
2746 * @effect_line: the #AgsEffectLine to add its default recall.
2747 * @output_pad_start: the start channel's index
2748 *
2749 * You may want the @effect_line to add its default recall. This function
2750 * may call ags_effect_line_find_port().
2751 *
2752 * Since: 3.0.0
2753 */
2754 void
ags_effect_line_map_recall(AgsEffectLine * effect_line,guint output_pad_start)2755 ags_effect_line_map_recall(AgsEffectLine *effect_line,
2756 guint output_pad_start)
2757 {
2758 g_return_if_fail(AGS_IS_EFFECT_LINE(effect_line));
2759
2760 g_object_ref((GObject *) effect_line);
2761 g_signal_emit((GObject *) effect_line,
2762 effect_line_signals[MAP_RECALL], 0,
2763 output_pad_start);
2764 g_object_unref((GObject *) effect_line);
2765 }
2766
2767 GList*
ags_effect_line_real_find_port(AgsEffectLine * effect_line)2768 ags_effect_line_real_find_port(AgsEffectLine *effect_line)
2769 {
2770 GList *port, *tmp_port;
2771 GList *line_member, *line_member_start;
2772
2773 if(effect_line == NULL ||
2774 effect_line->grid == NULL){
2775 return(NULL);
2776 }
2777
2778 line_member_start =
2779 line_member = gtk_container_get_children(GTK_CONTAINER(effect_line->grid));
2780
2781 port = NULL;
2782
2783 if(line_member != NULL){
2784 while(line_member != NULL){
2785 if(AGS_IS_LINE_MEMBER(line_member->data)){
2786 tmp_port = ags_line_member_find_port(AGS_LINE_MEMBER(line_member->data));
2787
2788 if(port != NULL){
2789 port = g_list_concat(port,
2790 tmp_port);
2791 }else{
2792 port = tmp_port;
2793 }
2794 }
2795
2796 line_member = line_member->next;
2797 }
2798
2799 g_list_free(line_member_start);
2800 }
2801
2802 return(port);
2803 }
2804
2805 /**
2806 * ags_effect_line_find_port:
2807 * @effect_line: the #AgsEffectLine
2808 *
2809 * Lookup ports of associated recalls.
2810 *
2811 * Returns: a #GList-struct containing all related #AgsPort
2812 *
2813 * Since: 3.0.0
2814 */
2815 GList*
ags_effect_line_find_port(AgsEffectLine * effect_line)2816 ags_effect_line_find_port(AgsEffectLine *effect_line)
2817 {
2818 GList *list;
2819
2820 list = NULL;
2821 g_return_val_if_fail(AGS_IS_EFFECT_LINE(effect_line),
2822 NULL);
2823
2824 g_object_ref((GObject *) effect_line);
2825 g_signal_emit((GObject *) effect_line,
2826 effect_line_signals[FIND_PORT], 0,
2827 &list);
2828 g_object_unref((GObject *) effect_line);
2829
2830 return(list);
2831 }
2832
2833 /**
2834 * ags_effect_line_done:
2835 * @effect_line: the #AgsEffectLine
2836 * @recall_id: the #AgsRecallID
2837 *
2838 * Notify about to stop playback of @recall_id.
2839 *
2840 * Since: 3.0.0
2841 */
2842 void
ags_effect_line_done(AgsEffectLine * effect_line,GObject * recall_id)2843 ags_effect_line_done(AgsEffectLine *effect_line, GObject *recall_id)
2844 {
2845 g_return_if_fail(AGS_IS_EFFECT_LINE(effect_line));
2846
2847 g_object_ref((GObject *) effect_line);
2848 g_signal_emit((GObject *) effect_line,
2849 effect_line_signals[DONE], 0,
2850 recall_id);
2851 g_object_unref((GObject *) effect_line);
2852 }
2853
2854 /**
2855 * ags_effect_line_find_next_grouped:
2856 * @effect_line: a #GList-struct of #AgsEffectLine objects
2857 *
2858 * Retrieve next grouped effect_line.
2859 *
2860 * Returns: next matching #GList-struct containing #AgsEffectLine
2861 *
2862 * Since: 3.0.0
2863 */
2864 GList*
ags_effect_line_find_next_grouped(GList * effect_line)2865 ags_effect_line_find_next_grouped(GList *effect_line)
2866 {
2867 while(effect_line != NULL && !gtk_toggle_button_get_active(AGS_EFFECT_LINE(effect_line->data)->group)){
2868 effect_line = effect_line->next;
2869 }
2870
2871 return(effect_line);
2872 }
2873
2874 /**
2875 * ags_effect_line_check_message:
2876 * @effect_line: the #AgsEffectLine
2877 *
2878 * Check message queue for message envelopes.
2879 *
2880 * Since: 3.0.0
2881 */
2882 void
ags_effect_line_check_message(AgsEffectLine * effect_line)2883 ags_effect_line_check_message(AgsEffectLine *effect_line)
2884 {
2885 AgsChannel *channel;
2886
2887 AgsMessageDelivery *message_delivery;
2888
2889 GList *start_message_envelope, *message_envelope;
2890
2891 if(!AGS_IS_EFFECT_LINE(effect_line)){
2892 return;
2893 }
2894
2895 /* retrieve message */
2896 message_delivery = ags_message_delivery_get_instance();
2897
2898 channel = effect_line->channel;
2899
2900 message_envelope =
2901 start_message_envelope = ags_message_delivery_find_sender(message_delivery,
2902 "libgsequencer",
2903 (GObject *) channel);
2904
2905 while(message_envelope != NULL){
2906 xmlNode *root_node;
2907
2908 root_node = xmlDocGetRootElement(AGS_MESSAGE_ENVELOPE(message_envelope->data)->doc);
2909
2910 if(!xmlStrncmp(root_node->name,
2911 "ags-command",
2912 12)){
2913 if(!xmlStrncmp(xmlGetProp(root_node,
2914 "method"),
2915 BAD_CAST "AgsChannel::set-samplerate",
2916 27)){
2917 guint samplerate;
2918 gint position;
2919
2920 position = ags_strv_index(AGS_MESSAGE_ENVELOPE(message_envelope->data)->parameter_name,
2921 "samplerate");
2922 samplerate = g_value_get_uint(&(AGS_MESSAGE_ENVELOPE(message_envelope->data)->value[position]));
2923
2924 /* set samplerate */
2925 g_object_set(effect_line,
2926 "samplerate", samplerate,
2927 NULL);
2928 }else if(!xmlStrncmp(xmlGetProp(root_node,
2929 "method"),
2930 BAD_CAST "AgsChannel::set-buffer-size",
2931 28)){
2932 guint buffer_size;
2933 gint position;
2934
2935 position = ags_strv_index(AGS_MESSAGE_ENVELOPE(message_envelope->data)->parameter_name,
2936 "buffer-size");
2937 buffer_size = g_value_get_uint(&(AGS_MESSAGE_ENVELOPE(message_envelope->data)->value[position]));
2938
2939 /* set buffer size */
2940 g_object_set(effect_line,
2941 "buffer-size", buffer_size,
2942 NULL);
2943 }else if(!xmlStrncmp(xmlGetProp(root_node,
2944 "method"),
2945 BAD_CAST "AgsChannel::set-format",
2946 23)){
2947 guint format;
2948 gint position;
2949
2950 position = ags_strv_index(AGS_MESSAGE_ENVELOPE(message_envelope->data)->parameter_name,
2951 "format");
2952 format = g_value_get_uint(&(AGS_MESSAGE_ENVELOPE(message_envelope->data)->value[position]));
2953
2954 /* set format */
2955 g_object_set(effect_line,
2956 "format", format,
2957 NULL);
2958 }else if(!xmlStrncmp(xmlGetProp(root_node,
2959 "method"),
2960 BAD_CAST "AgsChannel::done",
2961 16)){
2962 AgsRecallID *recall_id;
2963
2964 gint position;
2965
2966 position = ags_strv_index(AGS_MESSAGE_ENVELOPE(message_envelope->data)->parameter_name,
2967 "recall-id");
2968
2969 recall_id = g_value_get_object(&(AGS_MESSAGE_ENVELOPE(message_envelope->data)->value[position]));
2970
2971 /* done */
2972 ags_effect_line_done(effect_line,
2973 (GObject *) recall_id);
2974 }
2975 }
2976
2977 message_envelope = message_envelope->next;
2978 }
2979
2980 g_list_free_full(start_message_envelope,
2981 g_object_unref);
2982 }
2983
2984 /**
2985 * ags_effect_line_indicator_queue_draw_timeout:
2986 * @widget: the indicator widgt
2987 *
2988 * Queue draw widget
2989 *
2990 * Returns: %TRUE if proceed with redraw, otherwise %FALSE
2991 *
2992 * Since: 3.0.0
2993 */
2994 gboolean
ags_effect_line_indicator_queue_draw_timeout(GtkWidget * widget)2995 ags_effect_line_indicator_queue_draw_timeout(GtkWidget *widget)
2996 {
2997 AgsEffectLine *effect_line;
2998
2999 if(g_hash_table_lookup(ags_effect_line_indicator_queue_draw,
3000 widget) != NULL){
3001 GList *list, *list_start;
3002
3003 effect_line = (AgsEffectLine *) gtk_widget_get_ancestor(widget,
3004 AGS_TYPE_EFFECT_LINE);
3005
3006 list_start =
3007 list = gtk_container_get_children((GtkContainer *) AGS_EFFECT_LINE(effect_line)->grid);
3008
3009 /* check members */
3010 while(list != NULL){
3011 if(AGS_IS_LINE_MEMBER(list->data) &&
3012 (AGS_LINE_MEMBER(list->data)->widget_type == AGS_TYPE_VINDICATOR ||
3013 AGS_LINE_MEMBER(list->data)->widget_type == AGS_TYPE_HINDICATOR ||
3014 AGS_LINE_MEMBER(list->data)->widget_type == AGS_TYPE_LED)){
3015 AgsLineMember *line_member;
3016 GtkAdjustment *adjustment;
3017 GtkWidget *child;
3018
3019 AgsPort *current;
3020
3021 AgsPluginPort *plugin_port;
3022
3023 gdouble average_peak;
3024 gdouble lower, upper;
3025 gdouble range;
3026 gdouble peak;
3027 gboolean success;
3028
3029 GValue value = {0,};
3030
3031 GRecMutex *port_mutex;
3032 GRecMutex *plugin_port_mutex;
3033
3034 line_member = AGS_LINE_MEMBER(list->data);
3035 child = gtk_bin_get_child(GTK_BIN(line_member));
3036
3037 average_peak = 0.0;
3038
3039 /* play port */
3040 current = line_member->port;
3041
3042 if(current == NULL){
3043 list = list->next;
3044
3045 continue;
3046 }
3047
3048 /* check if output port and specifier matches */
3049 if(!ags_port_test_flags(current, AGS_PORT_IS_OUTPUT)){
3050 list = list->next;
3051
3052 continue;
3053 }
3054
3055 g_object_get(current,
3056 "plugin-port", &plugin_port,
3057 NULL);
3058
3059 if(plugin_port == NULL){
3060 list = list->next;
3061
3062 continue;
3063 }
3064
3065 g_object_unref(plugin_port);
3066
3067 /* get port mutex */
3068 port_mutex = AGS_PORT_GET_OBJ_MUTEX(current);
3069
3070 /* match specifier */
3071 g_rec_mutex_lock(port_mutex);
3072
3073 success = (!g_ascii_strcasecmp(current->specifier,
3074 line_member->specifier)) ? TRUE: FALSE;
3075
3076 g_rec_mutex_unlock(port_mutex);
3077
3078 if(!success){
3079 list = list->next;
3080
3081 continue;
3082 }
3083
3084 /* get plugin port mutex */
3085 plugin_port_mutex = AGS_PLUGIN_PORT_GET_OBJ_MUTEX(plugin_port);
3086
3087 /* lower and upper */
3088 g_rec_mutex_lock(plugin_port_mutex);
3089
3090 lower = g_value_get_float(plugin_port->lower_value);
3091 upper = g_value_get_float(plugin_port->upper_value);
3092
3093 g_rec_mutex_unlock(plugin_port_mutex);
3094
3095 /* get range */
3096 if(line_member->conversion != NULL){
3097 lower = ags_conversion_convert(line_member->conversion,
3098 lower,
3099 TRUE);
3100
3101 upper = ags_conversion_convert(line_member->conversion,
3102 upper,
3103 TRUE);
3104 }
3105
3106 range = upper - lower;
3107
3108 /* play port - read value */
3109 g_value_init(&value, G_TYPE_FLOAT);
3110 ags_port_safe_read(current,
3111 &value);
3112
3113 peak = g_value_get_float(&value);
3114 g_value_unset(&value);
3115
3116 if(line_member->conversion != NULL){
3117 peak = ags_conversion_convert(line_member->conversion,
3118 peak,
3119 TRUE);
3120 }
3121
3122 /* calculate peak */
3123 if(range == 0.0 ||
3124 current->port_value_type == G_TYPE_BOOLEAN){
3125 if(peak != 0.0){
3126 average_peak = 10.0;
3127 }
3128 }else{
3129 average_peak += ((1.0 / (range / peak)) * 10.0);
3130 }
3131
3132 /* recall port */
3133 current = line_member->recall_port;
3134
3135 /* recall port - read value */
3136 g_value_init(&value, G_TYPE_FLOAT);
3137 ags_port_safe_read(current,
3138 &value);
3139
3140 peak = g_value_get_float(&value);
3141 g_value_unset(&value);
3142
3143 if(line_member->conversion != NULL){
3144 peak = ags_conversion_convert(line_member->conversion,
3145 peak,
3146 TRUE);
3147 }
3148
3149 /* calculate peak */
3150 if(range == 0.0 ||
3151 current->port_value_type == G_TYPE_BOOLEAN){
3152 if(peak != 0.0){
3153 average_peak = 10.0;
3154 }
3155 }else{
3156 average_peak += ((1.0 / (range / peak)) * 10.0);
3157 }
3158
3159 /* apply */
3160 if(AGS_IS_LED(child)){
3161 if(average_peak != 0.0){
3162 ags_led_set_active((AgsLed *) child);
3163 }
3164 }else{
3165 g_object_get(child,
3166 "adjustment", &adjustment,
3167 NULL);
3168
3169 gtk_adjustment_set_value(adjustment,
3170 average_peak);
3171 }
3172 }
3173
3174 list = list->next;
3175 }
3176
3177 g_list_free(list_start);
3178
3179 /* queue draw */
3180 gtk_widget_queue_draw(widget);
3181
3182 return(TRUE);
3183 }else{
3184 return(FALSE);
3185 }
3186 }
3187
3188 /**
3189 * ags_effect_line_new:
3190 * @channel: the #AgsChannel to visualize
3191 *
3192 * Create a new instance of #AgsEffectLine
3193 *
3194 * Returns: the new #AgsEffectLine
3195 *
3196 * Since: 3.0.0
3197 */
3198 AgsEffectLine*
ags_effect_line_new(AgsChannel * channel)3199 ags_effect_line_new(AgsChannel *channel)
3200 {
3201 AgsEffectLine *effect_line;
3202
3203 effect_line = (AgsEffectLine *) g_object_new(AGS_TYPE_EFFECT_LINE,
3204 "channel", channel,
3205 NULL);
3206
3207 return(effect_line);
3208 }
3209