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_navigation.h>
21 #include <ags/X/ags_navigation_callbacks.h>
22
23 #include <ags/X/ags_ui_provider.h>
24 #include <ags/X/ags_window.h>
25 #include <ags/X/ags_notation_editor.h>
26
27 #include <ags/i18n.h>
28
29 void ags_navigation_class_init(AgsNavigationClass *navigation);
30 void ags_navigation_connectable_interface_init(AgsConnectableInterface *connectable);
31 void ags_navigation_init(AgsNavigation *navigation);
32 void ags_navigation_set_property(GObject *gobject,
33 guint prop_id,
34 const GValue *value,
35 GParamSpec *param_spec);
36 void ags_navigation_get_property(GObject *gobject,
37 guint prop_id,
38 GValue *value,
39 GParamSpec *param_spec);
40 void ags_navigation_finalize(GObject *gobject);
41
42 void ags_navigation_connect(AgsConnectable *connectable);
43 void ags_navigation_disconnect(AgsConnectable *connectable);
44
45 void ags_navigation_real_change_position(AgsNavigation *navigation,
46 gdouble tact);
47
48 /**
49 * SECTION:ags_navigation
50 * @short_description: control audio object's playback.
51 * @title: AgsNavigation
52 * @section_id:
53 * @include: ags/X/ags_navigation.h
54 *
55 * #AgsNavigation is a composite widget to control playback of #AgsAudio objects.
56 * It can start #AgsMachine in bulk mode or position the stream.
57 */
58
59 enum{
60 PROP_0,
61 PROP_SOUNDCARD,
62 };
63
64 enum{
65 CHANGE_POSITION,
66 LAST_SIGNAL,
67 };
68
69 static gpointer ags_navigation_parent_class = NULL;
70 static guint navigation_signals[LAST_SIGNAL];
71
72 GType
ags_navigation_get_type(void)73 ags_navigation_get_type(void)
74 {
75 static volatile gsize g_define_type_id__volatile = 0;
76
77 if(g_once_init_enter (&g_define_type_id__volatile)){
78 GType ags_type_navigation = 0;
79
80 static const GTypeInfo ags_navigation_info = {
81 sizeof (AgsNavigationClass),
82 NULL, /* base_init */
83 NULL, /* base_finalize */
84 (GClassInitFunc) ags_navigation_class_init,
85 NULL, /* class_finalize */
86 NULL, /* class_data */
87 sizeof (AgsNavigation),
88 0, /* n_preallocs */
89 (GInstanceInitFunc) ags_navigation_init,
90 };
91
92 static const GInterfaceInfo ags_connectable_interface_info = {
93 (GInterfaceInitFunc) ags_navigation_connectable_interface_init,
94 NULL, /* interface_finalize */
95 NULL, /* interface_data */
96 };
97
98 ags_type_navigation = g_type_register_static(GTK_TYPE_BOX,
99 "AgsNavigation", &ags_navigation_info,
100 0);
101
102 g_type_add_interface_static(ags_type_navigation,
103 AGS_TYPE_CONNECTABLE,
104 &ags_connectable_interface_info);
105
106 g_once_init_leave(&g_define_type_id__volatile, ags_type_navigation);
107 }
108
109 return g_define_type_id__volatile;
110 }
111
112 void
ags_navigation_class_init(AgsNavigationClass * navigation)113 ags_navigation_class_init(AgsNavigationClass *navigation)
114 {
115 GObjectClass *gobject;
116 GParamSpec *param_spec;
117
118 ags_navigation_parent_class = g_type_class_peek_parent(navigation);
119
120 /* GObjectClass */
121 gobject = (GObjectClass *) navigation;
122
123 gobject->set_property = ags_navigation_set_property;
124 gobject->get_property = ags_navigation_get_property;
125
126 gobject->finalize = ags_navigation_finalize;
127
128 /* properties */
129 /**
130 * AgsNavigation:soundcard:
131 *
132 * The assigned #AgsSoundcard to use as default sink.
133 *
134 * Since: 3.0.0
135 */
136 param_spec = g_param_spec_object("soundcard",
137 i18n_pspec("assigned soundcard"),
138 i18n_pspec("The soundcard it is assigned with"),
139 G_TYPE_OBJECT,
140 G_PARAM_READABLE | G_PARAM_WRITABLE);
141 g_object_class_install_property(gobject,
142 PROP_SOUNDCARD,
143 param_spec);
144
145 /* AgsNavigationClass */
146 navigation->change_position = ags_navigation_real_change_position;
147
148 /* signals */
149 /**
150 * AgsNavigation::change-position:
151 * @navigation: the #AgsNavigation
152 * @tact: the new position
153 *
154 * The ::change-position seeks the stream.
155 *
156 * Since: 3.0.0
157 */
158 navigation_signals[CHANGE_POSITION] =
159 g_signal_new("change-position",
160 G_TYPE_FROM_CLASS (navigation),
161 G_SIGNAL_RUN_LAST,
162 G_STRUCT_OFFSET (AgsNavigationClass, change_position),
163 NULL, NULL,
164 g_cclosure_marshal_VOID__DOUBLE,
165 G_TYPE_NONE, 1,
166 G_TYPE_DOUBLE);
167 }
168
169 void
ags_navigation_connectable_interface_init(AgsConnectableInterface * connectable)170 ags_navigation_connectable_interface_init(AgsConnectableInterface *connectable)
171 {
172 connectable->is_ready = NULL;
173 connectable->is_connected = NULL;
174 connectable->connect = ags_navigation_connect;
175 connectable->disconnect = ags_navigation_disconnect;
176 }
177
178 void
ags_navigation_init(AgsNavigation * navigation)179 ags_navigation_init(AgsNavigation *navigation)
180 {
181 GtkBox *hbox;
182 GtkLabel *label;
183
184 gtk_orientable_set_orientation(GTK_ORIENTABLE(navigation),
185 GTK_ORIENTATION_VERTICAL);
186
187 navigation->flags = AGS_NAVIGATION_BLOCK_TIC;
188
189 navigation->soundcard = NULL;
190
191 navigation->start_tact = 0.0;
192 navigation->note_offset = 0.0;
193
194 /* GtkWidget */
195 hbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,
196 0);
197 gtk_box_pack_start((GtkBox *) navigation,
198 (GtkWidget *) hbox,
199 FALSE, FALSE,
200 0);
201
202 navigation->expander_image = gtk_image_new_from_icon_name("down",
203 GTK_ICON_SIZE_LARGE_TOOLBAR);
204
205 navigation->expander = (GtkToggleButton *) gtk_toggle_button_new();
206 gtk_widget_set_name((GtkWidget *) navigation->expander,
207 "ags-navigation-expander");
208 gtk_box_pack_start((GtkBox*) hbox, (GtkWidget *) navigation->expander,
209 FALSE, FALSE,
210 0);
211 gtk_container_add((GtkContainer *) navigation->expander,
212 (GtkWidget *) navigation->expander_image);
213
214 label = (GtkLabel *) gtk_label_new(i18n("bpm"));
215 gtk_box_pack_start((GtkBox*) hbox,
216 (GtkWidget *) label,
217 FALSE, FALSE,
218 0);
219
220 navigation->bpm = (GtkSpinButton *) gtk_spin_button_new_with_range(1.0, 1000.0, 1.0);
221 gtk_spin_button_set_value(navigation->bpm, 120.0);
222 gtk_box_pack_start((GtkBox*) hbox,
223 (GtkWidget *) navigation->bpm,
224 FALSE, FALSE,
225 0);
226
227 navigation->current_bpm = 120.0;
228
229 navigation->rewind = (GtkToggleButton *) g_object_new(GTK_TYPE_BUTTON,
230 "image", (GtkWidget *) gtk_image_new_from_icon_name("media-skip-backward",
231 GTK_ICON_SIZE_LARGE_TOOLBAR),
232 NULL);
233 gtk_box_pack_start((GtkBox *) hbox,
234 (GtkWidget *) navigation->rewind,
235 FALSE, FALSE,
236 0);
237
238 navigation->previous = (GtkButton *) g_object_new(GTK_TYPE_BUTTON,
239 "image", (GtkWidget *) gtk_image_new_from_icon_name("media-seek-backward",
240 GTK_ICON_SIZE_LARGE_TOOLBAR),
241 NULL);
242 gtk_box_pack_start((GtkBox *) hbox,
243 (GtkWidget *) navigation->previous,
244 FALSE, FALSE,
245 0);
246
247 navigation->play = (GtkToggleButton *) g_object_new(GTK_TYPE_TOGGLE_BUTTON,
248 "image", (GtkWidget *) gtk_image_new_from_icon_name("media-playback-start",
249 GTK_ICON_SIZE_LARGE_TOOLBAR),
250 NULL);
251 gtk_box_pack_start((GtkBox *) hbox,
252 (GtkWidget *) navigation->play,
253 FALSE, FALSE,
254 0);
255
256 navigation->stop = (GtkButton *) g_object_new(GTK_TYPE_BUTTON,
257 "image", (GtkWidget *) gtk_image_new_from_icon_name("media-playback-stop",
258 GTK_ICON_SIZE_LARGE_TOOLBAR),
259 NULL);
260 gtk_box_pack_start((GtkBox *) hbox,
261 (GtkWidget *) navigation->stop,
262 FALSE, FALSE,
263 0);
264
265 navigation->next = (GtkButton *) g_object_new(GTK_TYPE_BUTTON,
266 "image", (GtkWidget *) gtk_image_new_from_icon_name("media-seek-forward",
267 GTK_ICON_SIZE_LARGE_TOOLBAR),
268 NULL);
269 gtk_box_pack_start((GtkBox *) hbox,
270 (GtkWidget *) navigation->next,
271 FALSE, FALSE,
272 0);
273
274 navigation->forward = (GtkToggleButton *) g_object_new(GTK_TYPE_BUTTON,
275 "image", (GtkWidget *) gtk_image_new_from_icon_name("media-skip-forward",
276 GTK_ICON_SIZE_LARGE_TOOLBAR),
277 NULL);
278 gtk_box_pack_start((GtkBox *) hbox,
279 (GtkWidget *) navigation->forward,
280 FALSE, FALSE,
281 0);
282
283 navigation->loop = (GtkCheckButton *) gtk_check_button_new_with_label(i18n("loop"));
284 gtk_box_pack_start((GtkBox *) hbox,
285 (GtkWidget *) navigation->loop,
286 FALSE, FALSE,
287 0);
288
289 label = (GtkLabel *) gtk_label_new("position");
290 gtk_box_pack_start((GtkBox *) hbox,
291 (GtkWidget *) label,
292 FALSE, FALSE,
293 0);
294
295 navigation->position_time = (GtkLabel *) gtk_label_new("00:00.000");
296 gtk_box_pack_start((GtkBox *) hbox,
297 (GtkWidget *) navigation->position_time,
298 FALSE, FALSE,
299 0);
300
301 navigation->position_tact = (GtkSpinButton *) gtk_spin_button_new_with_range(0.0, AGS_NOTATION_EDITOR_MAX_CONTROLS, 1.0);
302 gtk_box_pack_start((GtkBox *) hbox,
303 (GtkWidget *) navigation->position_tact,
304 FALSE, FALSE,
305 2);
306
307
308 label = (GtkLabel *) gtk_label_new("duration");
309 gtk_box_pack_start((GtkBox *) hbox,
310 (GtkWidget *) label,
311 FALSE, FALSE,
312 0);
313
314 navigation->duration_time = (GtkLabel *) gtk_label_new(NULL);
315 g_object_set(navigation->duration_time,
316 "label", "0000:00.000",
317 NULL);
318 gtk_box_pack_start((GtkBox *) hbox, (GtkWidget *) navigation->duration_time, FALSE, FALSE, 2);
319 g_timeout_add((guint) floor(AGS_UI_PROVIDER_DEFAULT_TIMEOUT * 1000.0), (GSourceFunc) ags_navigation_duration_time_queue_draw, (gpointer) navigation);
320
321 navigation->duration_tact = NULL;
322 // navigation->duration_tact = (GtkSpinButton *) gtk_spin_button_new_with_range(0.0, AGS_NOTATION_EDITOR_MAX_CONTROLS, 1.0);
323 // gtk_box_pack_start((GtkBox *) hbox, (GtkWidget *) navigation->duration_tact, FALSE, FALSE, 2);
324
325
326 /* expansion */
327 hbox = (GtkBox *) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,
328 0);
329 // GTK_WIDGET_SET_FLAGS((GtkWidget *) hbox, GTK_NO_SHOW_ALL);
330 gtk_box_pack_start((GtkBox *) navigation,
331 (GtkWidget *) hbox,
332 FALSE, FALSE,
333 0);
334
335 label = (GtkLabel *) gtk_label_new(i18n("loop L"));
336 gtk_box_pack_start((GtkBox *) hbox,
337 (GtkWidget *) label,
338 FALSE, FALSE,
339 0);
340
341 navigation->loop_left_tact = (GtkSpinButton *) gtk_spin_button_new_with_range(0.0, 65000.0, 1.0);
342 gtk_box_pack_start((GtkBox *) hbox,
343 (GtkWidget *) navigation->loop_left_tact,
344 FALSE, FALSE,
345 0);
346
347 label = (GtkLabel *) gtk_label_new(i18n("loop R"));
348 gtk_box_pack_start((GtkBox *) hbox,
349 (GtkWidget *) label,
350 FALSE, FALSE,
351 0);
352
353 navigation->loop_right_tact = (GtkSpinButton *) gtk_spin_button_new_with_range(0.0, 65000.0, 1.0);
354 gtk_spin_button_set_value(navigation->loop_right_tact,
355 4.0);
356 gtk_box_pack_start((GtkBox *) hbox,
357 (GtkWidget *) navigation->loop_right_tact,
358 FALSE, FALSE,
359 0);
360
361 navigation->scroll = NULL;
362 /*
363 navigation->scroll = (GtkCheckButton *) gtk_check_button_new_with_label(i18n("auto-scroll"));
364 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(navigation->scroll),
365 FALSE);
366 gtk_box_pack_start((GtkBox *) hbox, (GtkWidget *) navigation->scroll, FALSE, FALSE, 2);
367 */
368
369 navigation->exclude_sequencer = (GtkCheckButton *) gtk_check_button_new_with_label(i18n("exclude sequencers"));
370 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(navigation->exclude_sequencer),
371 TRUE);
372 gtk_box_pack_start((GtkBox *) hbox,
373 (GtkWidget *) navigation->exclude_sequencer,
374 FALSE, FALSE,
375 0);
376
377 }
378
379 void
ags_navigation_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)380 ags_navigation_set_property(GObject *gobject,
381 guint prop_id,
382 const GValue *value,
383 GParamSpec *param_spec)
384 {
385 AgsNavigation *navigation;
386
387 navigation = AGS_NAVIGATION(gobject);
388
389 switch(prop_id){
390 case PROP_SOUNDCARD:
391 {
392 GObject *soundcard;
393
394 soundcard = g_value_get_object(value);
395
396 if(navigation->soundcard == soundcard){
397 return;
398 }
399
400 if(navigation->soundcard != NULL){
401 g_object_unref(navigation->soundcard);
402 }
403
404 if(soundcard != NULL){
405 //FIXME:JK: no direct callback
406 g_signal_connect_after(soundcard, "stop",
407 G_CALLBACK(ags_navigation_soundcard_stop_callback), (gpointer) navigation);
408
409 g_object_ref(soundcard);
410 }
411
412 navigation->soundcard = soundcard;
413 }
414 break;
415 default:
416 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
417 break;
418 }
419 }
420
421 void
ags_navigation_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)422 ags_navigation_get_property(GObject *gobject,
423 guint prop_id,
424 GValue *value,
425 GParamSpec *param_spec)
426 {
427 AgsNavigation *navigation;
428
429 navigation = AGS_NAVIGATION(gobject);
430
431 switch(prop_id){
432 case PROP_SOUNDCARD:
433 g_value_set_object(value, navigation->soundcard);
434 break;
435 default:
436 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
437 break;
438 }
439 }
440
441 void
ags_navigation_finalize(GObject * gobject)442 ags_navigation_finalize(GObject *gobject)
443 {
444 /* call parent */
445 G_OBJECT_CLASS(ags_navigation_parent_class)->finalize(gobject);
446 }
447
448 void
ags_navigation_connect(AgsConnectable * connectable)449 ags_navigation_connect(AgsConnectable *connectable)
450 {
451 AgsNavigation *navigation;
452
453 navigation = AGS_NAVIGATION(connectable);
454
455 if((AGS_NAVIGATION_CONNECTED & (navigation->flags)) != 0){
456 return;
457 }
458
459 navigation->flags |= AGS_NAVIGATION_CONNECTED;
460
461 g_signal_connect((GObject *) navigation->expander, "clicked",
462 G_CALLBACK(ags_navigation_expander_callback), (gpointer) navigation);
463
464 g_signal_connect_after((GObject *) navigation->bpm, "value-changed",
465 G_CALLBACK(ags_navigation_bpm_callback), (gpointer) navigation);
466
467 g_signal_connect((GObject *) navigation->rewind, "clicked",
468 G_CALLBACK(ags_navigation_rewind_callback), (gpointer) navigation);
469
470 g_signal_connect((GObject *) navigation->previous, "clicked",
471 G_CALLBACK(ags_navigation_prev_callback), (gpointer) navigation);
472
473 g_signal_connect((GObject *) navigation->play, "clicked",
474 G_CALLBACK(ags_navigation_play_callback), (gpointer) navigation);
475
476 g_signal_connect((GObject *) navigation->stop, "clicked",
477 G_CALLBACK(ags_navigation_stop_callback), (gpointer) navigation);
478
479 g_signal_connect((GObject *) navigation->next, "clicked",
480 G_CALLBACK(ags_navigation_next_callback), (gpointer) navigation);
481
482 g_signal_connect((GObject *) navigation->forward, "clicked",
483 G_CALLBACK(ags_navigation_forward_callback), (gpointer) navigation);
484
485 g_signal_connect((GObject *) navigation->loop, "clicked",
486 G_CALLBACK(ags_navigation_loop_callback), (gpointer) navigation);
487
488 g_signal_connect_after((GObject *) navigation->position_tact, "value-changed",
489 G_CALLBACK(ags_navigation_position_tact_callback), (gpointer) navigation);
490
491 // g_signal_connect((GObject *) navigation->duration_tact, "value-changed",
492 // G_CALLBACK(ags_navigation_duration_tact_callback), (gpointer) navigation);
493
494 /* soundcard */
495 // g_signal_connect_after((GObject *) navigation->soundcard, "tic",
496 // G_CALLBACK(ags_navigation_tic_callback), (gpointer) navigation);
497
498 if(navigation->soundcard != NULL){
499 g_signal_connect_after(navigation->soundcard, "stop",
500 G_CALLBACK(ags_navigation_soundcard_stop_callback), (gpointer) navigation);
501 }
502
503 /* expansion */
504 g_signal_connect((GObject *) navigation->loop_left_tact, "value-changed",
505 G_CALLBACK(ags_navigation_loop_left_tact_callback), (gpointer) navigation);
506
507 g_signal_connect((GObject *) navigation->loop_right_tact, "value-changed",
508 G_CALLBACK(ags_navigation_loop_right_tact_callback), (gpointer) navigation);
509 }
510
511 void
ags_navigation_disconnect(AgsConnectable * connectable)512 ags_navigation_disconnect(AgsConnectable *connectable)
513 {
514 AgsNavigation *navigation;
515
516 navigation = AGS_NAVIGATION(connectable);
517
518 if((AGS_NAVIGATION_CONNECTED & (navigation->flags)) == 0){
519 return;
520 }
521
522 navigation->flags &= (~AGS_NAVIGATION_CONNECTED);
523
524 g_object_disconnect((GObject *) navigation->expander,
525 "clicked",
526 G_CALLBACK(ags_navigation_expander_callback),
527 (gpointer) navigation,
528 NULL);
529
530 g_object_disconnect((GObject *) navigation->bpm,
531 "value-changed",
532 G_CALLBACK(ags_navigation_bpm_callback),
533 (gpointer) navigation,
534 NULL);
535
536 g_object_disconnect((GObject *) navigation->rewind,
537 "clicked",
538 G_CALLBACK(ags_navigation_rewind_callback),
539 (gpointer) navigation,
540 NULL);
541
542 g_object_disconnect((GObject *) navigation->previous,
543 "clicked",
544 G_CALLBACK(ags_navigation_prev_callback),
545 (gpointer) navigation,
546 NULL);
547
548 g_object_disconnect((GObject *) navigation->play,
549 "clicked",
550 G_CALLBACK(ags_navigation_play_callback),
551 (gpointer) navigation,
552 NULL);
553
554 g_object_disconnect((GObject *) navigation->stop,
555 "clicked",
556 G_CALLBACK(ags_navigation_stop_callback),
557 (gpointer) navigation,
558 NULL);
559
560 g_object_disconnect((GObject *) navigation->next,
561 "clicked",
562 G_CALLBACK(ags_navigation_next_callback),
563 (gpointer) navigation,
564 NULL);
565
566 g_object_disconnect((GObject *) navigation->forward,
567 "clicked",
568 G_CALLBACK(ags_navigation_forward_callback),
569 (gpointer) navigation,
570 NULL);
571
572 g_object_disconnect((GObject *) navigation->loop,
573 "clicked",
574 G_CALLBACK(ags_navigation_loop_callback),
575 (gpointer) navigation,
576 NULL);
577
578 g_object_disconnect((GObject *) navigation->position_tact,
579 "value-changed",
580 G_CALLBACK(ags_navigation_position_tact_callback),
581 (gpointer) navigation,
582 NULL);
583
584 if(navigation->soundcard != NULL){
585 g_object_disconnect(navigation->soundcard,
586 "stop",
587 G_CALLBACK(ags_navigation_soundcard_stop_callback),
588 (gpointer) navigation,
589 NULL);
590 }
591
592 /* expansion */
593 g_object_disconnect((GObject *) navigation->loop_left_tact,
594 "value-changed",
595 G_CALLBACK(ags_navigation_loop_left_tact_callback),
596 (gpointer) navigation,
597 NULL);
598
599 g_object_disconnect((GObject *) navigation->loop_right_tact,
600 "value-changed",
601 G_CALLBACK(ags_navigation_loop_right_tact_callback),
602 (gpointer) navigation,
603 NULL);
604 }
605
606 void
ags_navigation_real_change_position(AgsNavigation * navigation,gdouble tact_counter)607 ags_navigation_real_change_position(AgsNavigation *navigation,
608 gdouble tact_counter)
609 {
610 AgsSeekSoundcard *seek_soundcard;
611
612 AgsApplicationContext *application_context;
613
614 GObject *default_soundcard;
615
616 GList *start_list, *list;
617
618 gchar *timestr;
619 gdouble delay;
620 gdouble delay_factor;
621 gint64 new_offset;
622
623 application_context = ags_application_context_get_instance();
624
625 default_soundcard = ags_sound_provider_get_default_soundcard(AGS_SOUND_PROVIDER(application_context));
626
627 /* seek soundcard */
628 delay = ags_soundcard_get_delay(AGS_SOUNDCARD(default_soundcard));
629 delay_factor = ags_soundcard_get_delay_factor(AGS_SOUNDCARD(default_soundcard));
630
631 new_offset = (16 * tact_counter);
632
633 seek_soundcard = ags_seek_soundcard_new(default_soundcard,
634 new_offset,
635 AGS_SEEK_SET);
636
637 ags_ui_provider_schedule_task(AGS_UI_PROVIDER(application_context),
638 (AgsTask *) seek_soundcard);
639
640 /* soundcard - start offset */
641 list =
642 start_list = ags_sound_provider_get_soundcard(AGS_SOUND_PROVIDER(application_context));
643
644 while(list != NULL){
645 ags_soundcard_set_start_note_offset(AGS_SOUNDCARD(list->data),
646 new_offset);
647
648 list = list->next;
649 }
650
651 g_list_free_full(start_list,
652 g_object_unref);
653
654 /* sequencer - start offset */
655 list =
656 start_list = ags_sound_provider_get_sequencer(AGS_SOUND_PROVIDER(application_context));
657
658 while(list != NULL){
659 ags_sequencer_set_start_note_offset(AGS_SEQUENCER(list->data),
660 new_offset);
661
662 list = list->next;
663 }
664
665 g_list_free_full(start_list,
666 g_object_unref);
667
668 //TODO:JK: implement me
669
670 /* update */
671 timestr = ags_time_get_uptime_from_offset(16.0 * tact_counter,
672 gtk_spin_button_get_value(navigation->bpm),
673 delay,
674 delay_factor);
675 gtk_label_set_text(navigation->position_time, timestr);
676
677 g_free(timestr);
678 }
679
680 /**
681 * ags_navigation_change_position:
682 * @navigation: the #AgsNavigation
683 * @tact: the new position
684 *
685 * Change tact position of editor. The scrollbar is adjustet
686 * and its playback position seeked.
687 *
688 * Since: 3.0.0
689 */
690 void
ags_navigation_change_position(AgsNavigation * navigation,gdouble tact)691 ags_navigation_change_position(AgsNavigation *navigation,
692 gdouble tact)
693 {
694 g_return_if_fail(AGS_IS_NAVIGATION(navigation));
695
696 g_object_ref(G_OBJECT(navigation));
697 g_signal_emit(G_OBJECT(navigation),
698 navigation_signals[CHANGE_POSITION], 0,
699 tact);
700 g_object_unref(G_OBJECT(navigation));
701 }
702
703 /**
704 * ags_navigation_tact_to_time_string:
705 * @tact: the new position
706 * @bpm: the BPM
707 * @delay_factor: the delay factor
708 *
709 * Convert tact unit to time.
710 *
711 * Returns: tact as time string
712 *
713 * Since: 3.0.0
714 */
715 gchar*
ags_navigation_tact_to_time_string(gdouble tact,gdouble bpm,gdouble delay_factor)716 ags_navigation_tact_to_time_string(gdouble tact,
717 gdouble bpm,
718 gdouble delay_factor)
719 {
720 gdouble delay_min, delay_sec, delay_msec;
721 gchar *timestr;
722 gdouble tact_redux;
723 guint min, sec, msec;
724
725 delay_min = bpm / delay_factor;
726 delay_sec = delay_min / 60.0;
727 delay_msec = delay_sec / 1000.0;
728
729 tact_redux = (tact + (tact / 16.0)) * 16.0;
730
731 min = (guint) floor(tact_redux / delay_min);
732
733 if(min > 0){
734 tact_redux = tact_redux - (min * delay_min);
735 }
736
737 sec = (guint) floor(tact_redux / delay_sec);
738
739 if(sec > 0){
740 tact_redux = tact_redux - (sec * delay_sec);
741 }
742
743 msec = (guint) floor(tact_redux / delay_msec);
744
745 timestr = g_strdup_printf("%.4d:%.2d.%.3d", min, sec, msec);
746
747 return(timestr);
748 }
749
750 /**
751 * ags_navigation_update_time_string:
752 * @tact: the new position
753 * @bpm: the BPM
754 * @delay_factor: the delay factor
755 * @time_string: the pointer location to set
756 *
757 * Updates time as string.
758 *
759 * Since: 3.0.0
760 */
761 void
ags_navigation_update_time_string(double tact,gdouble bpm,gdouble delay_factor,gchar * time_string)762 ags_navigation_update_time_string(double tact,
763 gdouble bpm,
764 gdouble delay_factor,
765 gchar *time_string)
766 {
767 gdouble delay_min, delay_sec, delay_msec;
768 gdouble tact_redux;
769 guint min, sec, msec;
770
771 delay_min = bpm * (60.0 / bpm) * (60.0 / bpm) * delay_factor;
772 delay_sec = delay_min / 60.0;
773 delay_msec = delay_sec / 1000.0;
774
775 tact_redux = 1.0 / 16.0;
776
777 min = (guint) floor(tact_redux / delay_min);
778
779 if(min > 0){
780 tact_redux = tact_redux - (min * delay_min);
781 }
782
783 sec = (guint) floor(tact_redux / delay_sec);
784
785 if(sec > 0){
786 tact_redux = tact_redux - (sec * delay_sec);
787 }
788
789 msec = (guint) floor(tact_redux / delay_msec);
790
791 sprintf(time_string, "%.4d:%.2d.%.3d", min, sec, msec);
792 }
793
794 gchar*
ags_navigation_relative_tact_to_time_string(gchar * timestr,gdouble delay,gdouble bpm,gdouble delay_factor)795 ags_navigation_relative_tact_to_time_string(gchar *timestr,
796 gdouble delay,
797 gdouble bpm,
798 gdouble delay_factor)
799 {
800 guint min, sec, msec;
801 guint prev_min, prev_sec, prev_msec;
802
803 gdouble sec_value;
804
805 sscanf(timestr, "%d:%d.%d", &prev_min, &prev_sec, &prev_msec);
806 sec_value = prev_min * 60.0;
807 sec_value += prev_sec;
808 sec_value += (1.0 / (16.0 * delay_factor) * (60.0 / bpm) + (1.0 / delay)) / 2.0;
809
810 if(prev_msec != 0){
811 sec_value += (prev_msec / 1000.0);
812 }
813
814 // sec_value += (1.0 / delay);
815
816 min = (guint) floor(sec_value / 60.0);
817
818 sec = sec_value - 60 * min;
819
820 msec = (sec_value - sec - min * 60) * 1000;
821
822 timestr = g_strdup_printf("%.4d:%.2d.%.3d", min, sec, msec);
823
824 return(timestr);
825 }
826
827 gchar*
ags_navigation_absolute_tact_to_time_string(gdouble tact,gdouble bpm,gdouble delay_factor)828 ags_navigation_absolute_tact_to_time_string(gdouble tact,
829 gdouble bpm,
830 gdouble delay_factor)
831 {
832 gchar *timestr;
833
834 gdouble delay_min, delay_sec, delay_msec;
835 gdouble tact_redux;
836 guint min, sec, msec;
837
838 /* calculate delays */
839 delay_sec = ((bpm / delay_factor) / 60.0);
840 delay_min = delay_sec * 60.0;
841 delay_msec = delay_sec / 1000.0;
842
843 /* translate to time string */
844 tact_redux = tact;
845
846 min = (guint) floor(tact_redux / delay_min);
847
848 if(min > 0){
849 tact_redux = tact_redux - (min * delay_min);
850 }
851
852 sec = (guint) floor(tact_redux / delay_sec);
853
854 if(sec > 0){
855 tact_redux = tact_redux - (sec * delay_sec);
856 }
857
858 msec = (guint) floor(tact_redux / delay_msec);
859
860 timestr = g_strdup_printf("%.4d:%.2d.%.3d", min, sec, msec);
861
862 return(timestr);
863 }
864
865 /**
866 * ags_navigation_set_seeking_sensitive_new:
867 * @navigation: the #AgsNavigation
868 * @enabled: if %TRUE then sensitive, otherwise insensitive.
869 *
870 * Enables/Disables the #AgsNavigation to control the tree.
871 *
872 * Since: 3.0.0
873 */
874 void
ags_navigation_set_seeking_sensitive(AgsNavigation * navigation,gboolean enabled)875 ags_navigation_set_seeking_sensitive(AgsNavigation *navigation,
876 gboolean enabled)
877 {
878 gtk_widget_set_sensitive((GtkWidget *) navigation->rewind,
879 enabled);
880 gtk_widget_set_sensitive((GtkWidget *) navigation->previous,
881 enabled);
882 gtk_widget_set_sensitive((GtkWidget *) navigation->play,
883 enabled);
884 gtk_widget_set_sensitive((GtkWidget *) navigation->stop,
885 enabled);
886 gtk_widget_set_sensitive((GtkWidget *) navigation->next,
887 enabled);
888 gtk_widget_set_sensitive((GtkWidget *) navigation->forward,
889 enabled);
890 }
891
892 gboolean
ags_navigation_duration_time_queue_draw(GtkWidget * widget)893 ags_navigation_duration_time_queue_draw(GtkWidget *widget)
894 {
895 AgsNavigation *navigation;
896
897 AgsApplicationContext *application_context;
898
899 GObject *default_soundcard;
900
901 gchar *str;
902
903 navigation = AGS_NAVIGATION(widget);
904
905 application_context = ags_application_context_get_instance();
906
907 default_soundcard = ags_sound_provider_get_default_soundcard(AGS_SOUND_PROVIDER(application_context));
908
909 if(default_soundcard != NULL){
910 str = ags_soundcard_get_uptime(AGS_SOUNDCARD(default_soundcard));
911
912 g_object_set(navigation->duration_time,
913 "label", str,
914 NULL);
915 g_free(str);
916
917 gtk_widget_queue_draw((GtkWidget *) navigation->duration_time);
918 }
919
920 return(TRUE);
921 }
922
923 /**
924 * ags_navigation_new:
925 *
926 * Create a new instance of #AgsNavigation to control the tree.
927 *
928 * Returns: the new #AgsNavigation
929 *
930 * Since: 3.0.0
931 */
932 AgsNavigation*
ags_navigation_new()933 ags_navigation_new()
934 {
935 AgsNavigation *navigation;
936
937 navigation = (AgsNavigation *) g_object_new(AGS_TYPE_NAVIGATION, NULL);
938
939 return(navigation);
940 }
941