2 Copyright (C) 2000 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
24 #include <cstdio> // for sprintf, grrr
30 #include <gtk/gtkaction.h>
32 #include "canvas/group.h"
33 #include "canvas/canvas.h"
35 #include "ardour/session.h"
36 #include "ardour/tempo.h"
37 #include "ardour/profile.h"
39 #include "gtkmm2ext/gtk_ui.h"
44 #include "gtk-custom-hruler.h"
45 #include "gui_thread.h"
46 #include "time_axis_view.h"
47 #include "editor_drag.h"
48 #include "editor_cursors.h"
52 using namespace ARDOUR;
55 using namespace Editing;
57 Editor *Editor::ruler_editor;
59 /* the order here must match the "metric" enums in editor.h */
61 GtkCustomMetric Editor::ruler_metrics[4] = {
62 {1, Editor::_metric_get_timecode },
63 {1, Editor::_metric_get_bbt },
64 {1, Editor::_metric_get_samples },
65 {1, Editor::_metric_get_minsec }
69 Editor::initialize_rulers ()
72 ruler_grabbed_widget = 0;
74 _ruler_separator = new Gtk::HSeparator();
75 _ruler_separator->set_size_request(-1, 2);
76 _ruler_separator->set_name("TimebarPadding");
77 _ruler_separator->show();
79 _minsec_ruler = gtk_custom_hruler_new ();
80 minsec_ruler = Glib::wrap (_minsec_ruler);
81 minsec_ruler->set_name ("MinSecRuler");
82 minsec_ruler->set_size_request (-1, (int)timebar_height);
83 gtk_custom_ruler_set_metric (GTK_CUSTOM_RULER(_minsec_ruler), &ruler_metrics[ruler_metric_minsec]);
84 minsec_ruler->hide ();
85 minsec_ruler->set_no_show_all();
87 _timecode_ruler = gtk_custom_hruler_new ();
88 timecode_ruler = Glib::wrap (_timecode_ruler);
89 timecode_ruler->set_name ("TimecodeRuler");
90 timecode_ruler->set_size_request (-1, (int)timebar_height);
91 gtk_custom_ruler_set_metric (GTK_CUSTOM_RULER(_timecode_ruler), &ruler_metrics[ruler_metric_timecode]);
92 timecode_ruler->hide ();
93 timecode_ruler->set_no_show_all();
96 _bbt_ruler = gtk_custom_hruler_new ();
97 bbt_ruler = Glib::wrap (_bbt_ruler);
98 bbt_ruler->set_name ("BBTRuler");
99 bbt_ruler->set_size_request (-1, (int)timebar_height);
100 gtk_custom_ruler_set_metric (GTK_CUSTOM_RULER(_bbt_ruler), &ruler_metrics[ruler_metric_bbt]);
102 bbt_ruler->set_no_show_all();
105 _samples_ruler = gtk_custom_hruler_new ();
106 samples_ruler = Glib::wrap (_samples_ruler);
107 samples_ruler->set_name ("SamplesRuler");
108 samples_ruler->set_size_request (-1, (int) timebar_height);
109 gtk_custom_ruler_set_metric (GTK_CUSTOM_RULER (_samples_ruler), &ruler_metrics[ruler_metric_samples]);
110 samples_ruler->hide ();
111 samples_ruler->set_no_show_all ();
113 _bbt_ruler = gtk_custom_hruler_new ();
114 bbt_ruler = Glib::wrap (_bbt_ruler);
115 bbt_ruler->set_name ("BBTRuler");
116 bbt_ruler->set_size_request (-1, (int)timebar_height);
117 gtk_custom_ruler_set_metric (GTK_CUSTOM_RULER(_bbt_ruler), &ruler_metrics[ruler_metric_bbt]);
119 bbt_ruler->set_no_show_all();
120 minsec_ruler->hide ();
121 minsec_ruler->set_no_show_all();
124 using namespace Box_Helpers;
125 BoxList & ruler_lab_children = ruler_label_vbox.children();
126 BoxList & ruler_children = time_canvas_vbox.children();
127 BoxList & lab_children = time_bars_vbox.children();
129 BoxList::iterator canvaspos = ruler_children.begin();
131 lab_children.push_back (Element(meter_label, PACK_SHRINK, PACK_START));
132 lab_children.push_back (Element(tempo_label, PACK_SHRINK, PACK_START));
133 lab_children.push_back (Element(range_mark_label, PACK_SHRINK, PACK_START));
134 lab_children.push_back (Element(transport_mark_label, PACK_SHRINK, PACK_START));
135 lab_children.push_back (Element(cd_mark_label, PACK_SHRINK, PACK_START));
136 lab_children.push_back (Element(mark_label, PACK_SHRINK, PACK_START));
137 lab_children.push_back (Element(videotl_label, PACK_SHRINK, PACK_START));
139 ruler_lab_children.push_back (Element(minsec_label, PACK_SHRINK, PACK_START));
140 ruler_children.insert (canvaspos, Element(*minsec_ruler, PACK_SHRINK, PACK_START));
141 ruler_lab_children.push_back (Element(timecode_label, PACK_SHRINK, PACK_START));
142 ruler_children.insert (canvaspos, Element(*timecode_ruler, PACK_SHRINK, PACK_START));
143 ruler_lab_children.push_back (Element(samples_label, PACK_SHRINK, PACK_START));
144 ruler_children.insert (canvaspos, Element (*samples_ruler, PACK_SHRINK, PACK_START));
145 ruler_lab_children.push_back (Element(bbt_label, PACK_SHRINK, PACK_START));
146 ruler_children.insert (canvaspos, Element(*bbt_ruler, PACK_SHRINK, PACK_START));
148 timecode_ruler->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::SCROLL_MASK);
149 bbt_ruler->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::SCROLL_MASK);
150 samples_ruler->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::SCROLL_MASK);
151 minsec_ruler->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::SCROLL_MASK);
153 timecode_ruler->signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_button_release));
154 bbt_ruler->signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_button_release));
155 samples_ruler->signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_button_release));
156 minsec_ruler->signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_button_release));
158 timecode_ruler->signal_button_press_event().connect (sigc::mem_fun(*this, &Editor::ruler_button_press));
159 bbt_ruler->signal_button_press_event().connect (sigc::mem_fun(*this, &Editor::ruler_button_press));
160 samples_ruler->signal_button_press_event().connect (sigc::mem_fun(*this, &Editor::ruler_button_press));
161 minsec_ruler->signal_button_press_event().connect (sigc::mem_fun(*this, &Editor::ruler_button_press));
163 timecode_ruler->signal_motion_notify_event().connect (sigc::mem_fun(*this, &Editor::ruler_mouse_motion));
164 bbt_ruler->signal_motion_notify_event().connect (sigc::mem_fun(*this, &Editor::ruler_mouse_motion));
165 samples_ruler->signal_motion_notify_event().connect (sigc::mem_fun(*this, &Editor::ruler_mouse_motion));
166 minsec_ruler->signal_motion_notify_event().connect (sigc::mem_fun(*this, &Editor::ruler_mouse_motion));
168 timecode_ruler->signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::ruler_scroll));
169 bbt_ruler->signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::ruler_scroll));
170 samples_ruler->signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::ruler_scroll));
171 minsec_ruler->signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::ruler_scroll));
173 visible_timebars = 0; /*this will be changed below */
177 Editor::ruler_scroll (GdkEventScroll* event)
180 int direction = event->direction;
181 bool handled = false;
185 temporal_zoom_step (false);
189 case GDK_SCROLL_DOWN:
190 temporal_zoom_step (true);
194 case GDK_SCROLL_LEFT:
195 xdelta = (current_page_samples() / 2);
196 if (leftmost_frame > xdelta) {
197 reset_x_origin (leftmost_frame - xdelta);
204 case GDK_SCROLL_RIGHT:
205 xdelta = (current_page_samples() / 2);
206 if (max_framepos - xdelta > leftmost_frame) {
207 reset_x_origin (leftmost_frame + xdelta);
209 reset_x_origin (max_framepos - current_page_samples());
224 Editor::ruler_button_press (GdkEventButton* ev)
230 Widget * grab_widget = 0;
232 if (timecode_ruler->is_realized() && ev->window == timecode_ruler->get_window()->gobj()) {
233 grab_widget = timecode_ruler;
234 } else if (bbt_ruler->is_realized() && ev->window == bbt_ruler->get_window()->gobj()) {
235 grab_widget = bbt_ruler;
236 } else if (samples_ruler->is_realized() && ev->window == samples_ruler->get_window()->gobj()) {
237 grab_widget = samples_ruler;
238 } else if (minsec_ruler->is_realized() && ev->window == minsec_ruler->get_window()->gobj()) {
239 grab_widget = minsec_ruler;
243 grab_widget->add_modal_grab ();
244 ruler_grabbed_widget = grab_widget;
247 if (ev->button == 1) {
248 // Since we will locate the playhead on button release, cancel any running
250 if (_session->is_auditioning()) {
251 _session->cancel_audition ();
254 /* playhead cursor drag: CursorDrag expects an event with
255 * canvas coordinates, so convert from window coordinates,
256 * since for now, rulers are still Gtk::Widgets.
259 GdkEventButton canvas_ev = *ev;
260 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (ev->x, ev->y));
261 canvas_ev.x = rint (d.x);
262 canvas_ev.y = rint (d.y);
264 _drags->set (new CursorDrag (this, *playhead_cursor, false), reinterpret_cast<GdkEvent *> (&canvas_ev));
265 _dragging_playhead = true;
272 Editor::ruler_button_release (GdkEventButton* ev)
278 if (_drags->active ()) {
279 GdkEventButton canvas_ev = *ev;
280 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (ev->x, ev->y));
281 canvas_ev.x = rint (d.x);
282 canvas_ev.x = rint (d.y);
283 _drags->end_grab (reinterpret_cast<GdkEvent*> (&canvas_ev));
284 _dragging_playhead = false;
287 if (ev->button == 3) {
289 stop_canvas_autoscroll();
291 framepos_t where = window_event_sample ((GdkEvent*) ev);
294 popup_ruler_menu (where);
297 if (ruler_grabbed_widget) {
298 ruler_grabbed_widget->remove_modal_grab();
299 ruler_grabbed_widget = 0;
306 Editor::ruler_label_button_release (GdkEventButton* ev)
308 if (ev->button == 3) {
309 Gtk::Menu* m = dynamic_cast<Gtk::Menu*> (ActionManager::get_widget (X_("/RulerMenuPopup")));
311 m->popup (1, ev->time);
320 Editor::ruler_mouse_motion (GdkEventMotion* ev)
326 if (_drags->active ()) {
327 GdkEventMotion canvas_ev = *ev;
328 ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (ev->x, ev->y));
329 canvas_ev.x = rint (d.x);
330 canvas_ev.y = rint (d.y);
331 _drags->window_motion_handler (reinterpret_cast<GdkEvent*> (&canvas_ev), false);
339 Editor::popup_ruler_menu (framepos_t where, ItemType t)
341 using namespace Menu_Helpers;
343 if (editor_ruler_menu == 0) {
344 editor_ruler_menu = new Menu;
345 editor_ruler_menu->set_name ("ArdourContextMenu");
348 // always build from scratch
349 MenuList& ruler_items = editor_ruler_menu->items();
350 editor_ruler_menu->set_name ("ArdourContextMenu");
355 ruler_items.push_back (MenuElem (_("New location marker"), sigc::bind ( sigc::mem_fun(*this, &Editor::mouse_add_new_marker), where, false, false)));
356 ruler_items.push_back (MenuElem (_("Clear all locations"), sigc::mem_fun(*this, &Editor::clear_markers)));
357 ruler_items.push_back (MenuElem (_("Unhide locations"), sigc::mem_fun(*this, &Editor::unhide_markers)));
358 ruler_items.push_back (SeparatorElem ());
360 case RangeMarkerBarItem:
361 ruler_items.push_back (MenuElem (_("New range"), sigc::bind (sigc::mem_fun (*this, &Editor::mouse_add_new_range), where)));
362 ruler_items.push_back (MenuElem (_("Clear all ranges"), sigc::mem_fun(*this, &Editor::clear_ranges)));
363 ruler_items.push_back (MenuElem (_("Unhide ranges"), sigc::mem_fun(*this, &Editor::unhide_ranges)));
364 ruler_items.push_back (SeparatorElem ());
367 case TransportMarkerBarItem:
371 case CdMarkerBarItem:
373 ruler_items.push_back (MenuElem (_("New CD track marker"), sigc::bind ( sigc::mem_fun(*this, &Editor::mouse_add_new_marker), where, true, false)));
378 ruler_items.push_back (MenuElem (_("New Tempo"), sigc::bind ( sigc::mem_fun(*this, &Editor::mouse_add_new_tempo_event), where)));
379 ruler_items.push_back (SeparatorElem ());
383 ruler_items.push_back (MenuElem (_("New Meter"), sigc::bind ( sigc::mem_fun(*this, &Editor::mouse_add_new_meter_event), where)));
384 ruler_items.push_back (SeparatorElem ());
388 ruler_items.push_back (MenuElem (_("Timeline height")));
389 static_cast<MenuItem*>(&ruler_items.back())->set_sensitive(false);
390 ruler_items.push_back (CheckMenuElem (_("Large"), sigc::bind ( sigc::mem_fun(*this, &Editor::set_video_timeline_height), 6)));
391 if (videotl_bar_height == 6) { static_cast<Gtk::CheckMenuItem*>(&ruler_items.back())->set_active(true);}
392 ruler_items.push_back (CheckMenuElem (_("Normal"), sigc::bind ( sigc::mem_fun(*this, &Editor::set_video_timeline_height), 4)));
393 if (videotl_bar_height == 4) { static_cast<Gtk::CheckMenuItem*>(&ruler_items.back())->set_active(true);}
394 ruler_items.push_back (CheckMenuElem (_("Small"), sigc::bind ( sigc::mem_fun(*this, &Editor::set_video_timeline_height), 3)));
395 if (videotl_bar_height == 3) { static_cast<Gtk::CheckMenuItem*>(&ruler_items.back())->set_active(true);}
396 ruler_items.push_back (SeparatorElem ());
398 ruler_items.push_back (MenuElem (_("Align Video Track")));
399 static_cast<MenuItem*>(&ruler_items.back())->set_sensitive(false);
401 ruler_items.push_back (CheckMenuElem (_("Lock")));
403 Gtk::CheckMenuItem* vtl_lock = static_cast<Gtk::CheckMenuItem*>(&ruler_items.back());
404 vtl_lock->set_active(is_video_timeline_locked());
405 vtl_lock->signal_activate().connect (sigc::mem_fun(*this, &Editor::toggle_video_timeline_locked));
408 ruler_items.push_back (SeparatorElem ());
415 Glib::RefPtr<Action> action;
417 action = ActionManager::get_action ("Rulers", "toggle-minsec-ruler");
419 ruler_items.push_back (MenuElem (*action->create_menu_item()));
421 if (!Profile->get_sae()) {
422 action = ActionManager::get_action ("Rulers", "toggle-timecode-ruler");
424 ruler_items.push_back (MenuElem (*action->create_menu_item()));
427 action = ActionManager::get_action ("Rulers", "toggle-samples-ruler");
429 ruler_items.push_back (MenuElem (*action->create_menu_item()));
431 action = ActionManager::get_action ("Rulers", "toggle-bbt-ruler");
433 ruler_items.push_back (MenuElem (*action->create_menu_item()));
435 action = ActionManager::get_action ("Rulers", "toggle-meter-ruler");
437 ruler_items.push_back (MenuElem (*action->create_menu_item()));
439 action = ActionManager::get_action ("Rulers", "toggle-tempo-ruler");
441 ruler_items.push_back (MenuElem (*action->create_menu_item()));
443 if (!Profile->get_sae()) {
444 action = ActionManager::get_action ("Rulers", "toggle-range-ruler");
446 ruler_items.push_back (MenuElem (*action->create_menu_item()));
449 action = ActionManager::get_action ("Rulers", "toggle-loop-punch-ruler");
451 ruler_items.push_back (MenuElem (*action->create_menu_item()));
453 action = ActionManager::get_action ("Rulers", "toggle-cd-marker-ruler");
455 ruler_items.push_back (MenuElem (*action->create_menu_item()));
457 action = ActionManager::get_action ("Rulers", "toggle-marker-ruler");
459 ruler_items.push_back (MenuElem (*action->create_menu_item()));
461 action = ActionManager::get_action ("Rulers", "toggle-video-ruler");
463 ruler_items.push_back (MenuElem (*action->create_menu_item()));
466 editor_ruler_menu->popup (1, gtk_get_current_event_time());
468 no_ruler_shown_update = false;
472 Editor::store_ruler_visibility ()
474 XMLNode* node = new XMLNode(X_("RulerVisibility"));
476 node->add_property (X_("timecode"), ruler_timecode_action->get_active() ? "yes": "no");
477 node->add_property (X_("bbt"), ruler_bbt_action->get_active() ? "yes": "no");
478 node->add_property (X_("samples"), ruler_samples_action->get_active() ? "yes": "no");
479 node->add_property (X_("minsec"), ruler_minsec_action->get_active() ? "yes": "no");
480 node->add_property (X_("tempo"), ruler_tempo_action->get_active() ? "yes": "no");
481 node->add_property (X_("meter"), ruler_meter_action->get_active() ? "yes": "no");
482 node->add_property (X_("marker"), ruler_marker_action->get_active() ? "yes": "no");
483 node->add_property (X_("rangemarker"), ruler_range_action->get_active() ? "yes": "no");
484 node->add_property (X_("transportmarker"), ruler_loop_punch_action->get_active() ? "yes": "no");
485 node->add_property (X_("cdmarker"), ruler_cd_marker_action->get_active() ? "yes": "no");
486 node->add_property (X_("videotl"), ruler_video_action->get_active() ? "yes": "no");
488 _session->add_extra_xml (*node);
489 _session->set_dirty ();
493 Editor::restore_ruler_visibility ()
496 XMLNode * node = _session->extra_xml (X_("RulerVisibility"));
498 no_ruler_shown_update = true;
501 if ((prop = node->property ("timecode")) != 0) {
502 if (string_is_affirmative (prop->value())) {
503 ruler_timecode_action->set_active (true);
505 ruler_timecode_action->set_active (false);
508 if ((prop = node->property ("bbt")) != 0) {
509 if (string_is_affirmative (prop->value())) {
510 ruler_bbt_action->set_active (true);
512 ruler_bbt_action->set_active (false);
515 if ((prop = node->property ("samples")) != 0) {
516 if (string_is_affirmative (prop->value())) {
517 ruler_samples_action->set_active (true);
519 ruler_samples_action->set_active (false);
522 if ((prop = node->property ("minsec")) != 0) {
523 if (string_is_affirmative (prop->value())) {
524 ruler_minsec_action->set_active (true);
526 ruler_minsec_action->set_active (false);
529 if ((prop = node->property ("tempo")) != 0) {
530 if (string_is_affirmative (prop->value())) {
531 ruler_tempo_action->set_active (true);
533 ruler_tempo_action->set_active (false);
536 if ((prop = node->property ("meter")) != 0) {
537 if (string_is_affirmative (prop->value())) {
538 ruler_meter_action->set_active (true);
540 ruler_meter_action->set_active (false);
543 if ((prop = node->property ("marker")) != 0) {
544 if (string_is_affirmative (prop->value())) {
545 ruler_marker_action->set_active (true);
547 ruler_marker_action->set_active (false);
550 if ((prop = node->property ("rangemarker")) != 0) {
551 if (string_is_affirmative (prop->value())) {
552 ruler_range_action->set_active (true);
554 ruler_range_action->set_active (false);
558 if ((prop = node->property ("transportmarker")) != 0) {
559 if (string_is_affirmative (prop->value())) {
560 ruler_loop_punch_action->set_active (true);
562 ruler_loop_punch_action->set_active (false);
566 if ((prop = node->property ("cdmarker")) != 0) {
567 if (string_is_affirmative (prop->value())) {
568 ruler_cd_marker_action->set_active (true);
570 ruler_cd_marker_action->set_active (false);
574 // this _session doesn't yet know about the cdmarker ruler
575 // as a benefit to the user who doesn't know the feature exists, show the ruler if
576 // any cd marks exist
577 ruler_cd_marker_action->set_active (false);
578 const Locations::LocationList & locs = _session->locations()->list();
579 for (Locations::LocationList::const_iterator i = locs.begin(); i != locs.end(); ++i) {
580 if ((*i)->is_cd_marker()) {
581 ruler_cd_marker_action->set_active (true);
587 if ((prop = node->property ("videotl")) != 0) {
588 if (string_is_affirmative (prop->value())) {
589 ruler_video_action->set_active (true);
591 ruler_video_action->set_active (false);
597 no_ruler_shown_update = false;
598 update_ruler_visibility ();
602 Editor::update_ruler_visibility ()
604 int visible_rulers = 0;
606 if (no_ruler_shown_update) {
610 visible_timebars = 0;
612 if (ruler_minsec_action->get_active()) {
614 minsec_label.show ();
615 minsec_ruler->show ();
617 minsec_label.hide ();
618 minsec_ruler->hide ();
621 if (ruler_timecode_action->get_active()) {
623 timecode_label.show ();
624 timecode_ruler->show ();
626 timecode_label.hide ();
627 timecode_ruler->hide ();
630 if (ruler_samples_action->get_active()) {
632 samples_label.show ();
633 samples_ruler->show ();
635 samples_label.hide ();
636 samples_ruler->hide ();
639 if (ruler_bbt_action->get_active()) {
653 /* gtk update probs require this (damn) */
656 range_mark_label.hide();
657 transport_mark_label.hide();
658 cd_mark_label.hide();
660 videotl_label.hide();
662 if (ruler_meter_action->get_active()) {
663 old_unit_pos = meter_group->position().y;
664 if (tbpos != old_unit_pos) {
665 meter_group->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos));
669 tbpos += timebar_height;
670 tbgpos += timebar_height;
677 if (ruler_tempo_action->get_active()) {
678 old_unit_pos = tempo_group->position().y;
679 if (tbpos != old_unit_pos) {
680 tempo_group->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos));
684 tbpos += timebar_height;
685 tbgpos += timebar_height;
692 if (!Profile->get_sae() && ruler_range_action->get_active()) {
693 old_unit_pos = range_marker_group->position().y;
694 if (tbpos != old_unit_pos) {
695 range_marker_group->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos));
697 range_marker_group->show();
698 range_mark_label.show();
700 tbpos += timebar_height;
701 tbgpos += timebar_height;
704 range_marker_group->hide();
705 range_mark_label.hide();
708 if (ruler_loop_punch_action->get_active()) {
709 old_unit_pos = transport_marker_group->position().y;
710 if (tbpos != old_unit_pos) {
711 transport_marker_group->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos));
713 transport_marker_group->show();
714 transport_mark_label.show();
715 tbpos += timebar_height;
716 tbgpos += timebar_height;
719 transport_marker_group->hide();
720 transport_mark_label.hide();
723 if (ruler_cd_marker_action->get_active()) {
724 old_unit_pos = cd_marker_group->position().y;
725 if (tbpos != old_unit_pos) {
726 cd_marker_group->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos));
728 cd_marker_group->show();
729 cd_mark_label.show();
730 tbpos += timebar_height;
731 tbgpos += timebar_height;
733 // make sure all cd markers show up in their respective places
734 update_cd_marker_display();
736 cd_marker_group->hide();
737 cd_mark_label.hide();
738 // make sure all cd markers show up in their respective places
739 update_cd_marker_display();
742 if (ruler_marker_action->get_active()) {
743 old_unit_pos = marker_group->position().y;
744 if (tbpos != old_unit_pos) {
745 marker_group->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos));
747 marker_group->show();
749 tbpos += timebar_height;
750 tbgpos += timebar_height;
753 marker_group->hide();
757 if (ruler_video_action->get_active()) {
758 old_unit_pos = videotl_group->position().y;
759 if (tbpos != old_unit_pos) {
760 videotl_group->move (ArdourCanvas::Duple (0.0, tbpos - old_unit_pos));
762 videotl_group->show();
763 videotl_label.show();
764 tbpos += timebar_height * videotl_bar_height;
765 tbgpos += timebar_height * videotl_bar_height;
766 visible_timebars+=videotl_bar_height;
767 queue_visual_videotimeline_update();
769 videotl_group->hide();
770 videotl_label.hide();
771 update_video_timeline(true);
774 ruler_label_vbox.set_size_request (-1, (int)(timebar_height * visible_rulers));
775 time_canvas_vbox.set_size_request (-1,-1);
777 std::cerr << "place HV group at " << timebar_height * visible_timebars << std::endl;
779 hv_scroll_group->set_y_position (timebar_height * visible_timebars);
781 compute_fixed_ruler_scale ();
782 update_fixed_rulers();
783 redisplay_tempo (false);
785 /* Changing ruler visibility means that any lines on markers might need updating */
786 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
787 i->second->setup_lines ();
792 Editor::update_just_timecode ()
794 ENSURE_GUI_THREAD (*this, &Editor::update_just_timecode)
800 framepos_t rightmost_frame = leftmost_frame + current_page_samples();
802 if (ruler_timecode_action->get_active()) {
803 gtk_custom_ruler_set_range (GTK_CUSTOM_RULER(_timecode_ruler), leftmost_frame, rightmost_frame,
804 leftmost_frame, _session->current_end_frame());
809 Editor::compute_fixed_ruler_scale ()
815 if (ruler_timecode_action->get_active()) {
816 set_timecode_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
819 if (ruler_minsec_action->get_active()) {
820 set_minsec_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
823 if (ruler_samples_action->get_active()) {
824 set_samples_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
829 Editor::update_fixed_rulers ()
831 framepos_t rightmost_frame;
837 compute_fixed_ruler_scale ();
839 ruler_metrics[ruler_metric_timecode].units_per_pixel = samples_per_pixel;
840 ruler_metrics[ruler_metric_samples].units_per_pixel = samples_per_pixel;
841 ruler_metrics[ruler_metric_minsec].units_per_pixel = samples_per_pixel;
843 rightmost_frame = leftmost_frame + current_page_samples();
845 /* these force a redraw, which in turn will force execution of the metric callbacks
846 to compute the relevant ticks to display.
849 if (ruler_timecode_action->get_active()) {
850 gtk_custom_ruler_set_range (GTK_CUSTOM_RULER(_timecode_ruler), leftmost_frame, rightmost_frame,
851 leftmost_frame, _session->current_end_frame());
854 if (ruler_samples_action->get_active()) {
855 gtk_custom_ruler_set_range (GTK_CUSTOM_RULER (_samples_ruler), leftmost_frame, rightmost_frame,
856 leftmost_frame, _session->current_end_frame());
859 if (ruler_minsec_action->get_active()) {
860 gtk_custom_ruler_set_range (GTK_CUSTOM_RULER(_minsec_ruler), leftmost_frame, rightmost_frame,
861 leftmost_frame, _session->current_end_frame());
866 Editor::update_tempo_based_rulers (ARDOUR::TempoMap::BBTPointList::const_iterator& begin,
867 ARDOUR::TempoMap::BBTPointList::const_iterator& end)
873 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame+current_page_samples(),
876 ruler_metrics[ruler_metric_bbt].units_per_pixel = samples_per_pixel;
878 if (ruler_bbt_action->get_active()) {
879 gtk_custom_ruler_set_range (GTK_CUSTOM_RULER(_bbt_ruler), leftmost_frame, leftmost_frame+current_page_samples(),
880 leftmost_frame, _session->current_end_frame());
884 /* Mark generation */
887 Editor::_metric_get_timecode (GtkCustomRulerMark **marks, gdouble lower, gdouble upper, gint maxchars)
889 return ruler_editor->metric_get_timecode (marks, lower, upper, maxchars);
893 Editor::_metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble upper, gint maxchars)
895 return ruler_editor->metric_get_bbt (marks, lower, upper, maxchars);
899 Editor::_metric_get_samples (GtkCustomRulerMark **marks, gdouble lower, gdouble upper, gint maxchars)
901 return ruler_editor->metric_get_samples (marks, lower, upper, maxchars);
905 Editor::_metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble upper, gint maxchars)
907 return ruler_editor->metric_get_minsec (marks, lower, upper, maxchars);
911 Editor::set_timecode_ruler_scale (framepos_t lower, framepos_t upper)
920 fr = _session->frame_rate();
922 if (lower > (spacer = (framepos_t) (128 * Editor::get_current_zoom ()))) {
923 lower = lower - spacer;
927 upper = upper + spacer;
928 framecnt_t const range = upper - lower;
930 if (range < (2 * _session->frames_per_timecode_frame())) { /* 0 - 2 frames */
931 timecode_ruler_scale = timecode_show_bits;
932 timecode_mark_modulo = 20;
933 timecode_nmarks = 2 + (2 * _session->config.get_subframes_per_frame());
934 } else if (range <= (fr / 4)) { /* 2 frames - 0.250 second */
935 timecode_ruler_scale = timecode_show_frames;
936 timecode_mark_modulo = 1;
937 timecode_nmarks = 2 + (range / (framepos_t)_session->frames_per_timecode_frame());
938 } else if (range <= (fr / 2)) { /* 0.25-0.5 second */
939 timecode_ruler_scale = timecode_show_frames;
940 timecode_mark_modulo = 2;
941 timecode_nmarks = 2 + (range / (framepos_t)_session->frames_per_timecode_frame());
942 } else if (range <= fr) { /* 0.5-1 second */
943 timecode_ruler_scale = timecode_show_frames;
944 timecode_mark_modulo = 5;
945 timecode_nmarks = 2 + (range / (framepos_t)_session->frames_per_timecode_frame());
946 } else if (range <= 2 * fr) { /* 1-2 seconds */
947 timecode_ruler_scale = timecode_show_frames;
948 timecode_mark_modulo = 10;
949 timecode_nmarks = 2 + (range / (framepos_t)_session->frames_per_timecode_frame());
950 } else if (range <= 8 * fr) { /* 2-8 seconds */
951 timecode_ruler_scale = timecode_show_seconds;
952 timecode_mark_modulo = 1;
953 timecode_nmarks = 2 + (range / fr);
954 } else if (range <= 16 * fr) { /* 8-16 seconds */
955 timecode_ruler_scale = timecode_show_seconds;
956 timecode_mark_modulo = 2;
957 timecode_nmarks = 2 + (range / fr);
958 } else if (range <= 30 * fr) { /* 16-30 seconds */
959 timecode_ruler_scale = timecode_show_seconds;
960 timecode_mark_modulo = 5;
961 timecode_nmarks = 2 + (range / fr);
962 } else if (range <= 60 * fr) { /* 30-60 seconds */
963 timecode_ruler_scale = timecode_show_seconds;
964 timecode_mark_modulo = 5;
965 timecode_nmarks = 2 + (range / fr);
966 } else if (range <= 2 * 60 * fr) { /* 1-2 minutes */
967 timecode_ruler_scale = timecode_show_seconds;
968 timecode_mark_modulo = 15;
969 timecode_nmarks = 2 + (range / fr);
970 } else if (range <= 4 * 60 * fr) { /* 2-4 minutes */
971 timecode_ruler_scale = timecode_show_seconds;
972 timecode_mark_modulo = 30;
973 timecode_nmarks = 2 + (range / fr);
974 } else if (range <= 10 * 60 * fr) { /* 4-10 minutes */
975 timecode_ruler_scale = timecode_show_minutes;
976 timecode_mark_modulo = 2;
977 timecode_nmarks = 2 + 10;
978 } else if (range <= 30 * 60 * fr) { /* 10-30 minutes */
979 timecode_ruler_scale = timecode_show_minutes;
980 timecode_mark_modulo = 5;
981 timecode_nmarks = 2 + 30;
982 } else if (range <= 60 * 60 * fr) { /* 30 minutes - 1hr */
983 timecode_ruler_scale = timecode_show_minutes;
984 timecode_mark_modulo = 10;
985 timecode_nmarks = 2 + 60;
986 } else if (range <= 4 * 60 * 60 * fr) { /* 1 - 4 hrs*/
987 timecode_ruler_scale = timecode_show_minutes;
988 timecode_mark_modulo = 30;
989 timecode_nmarks = 2 + (60 * 4);
990 } else if (range <= 8 * 60 * 60 * fr) { /* 4 - 8 hrs*/
991 timecode_ruler_scale = timecode_show_hours;
992 timecode_mark_modulo = 1;
993 timecode_nmarks = 2 + 8;
994 } else if (range <= 16 * 60 * 60 * fr) { /* 16-24 hrs*/
995 timecode_ruler_scale = timecode_show_hours;
996 timecode_mark_modulo = 1;
997 timecode_nmarks = 2 + 24;
1000 /* not possible if framepos_t is a 32 bit quantity */
1002 timecode_ruler_scale = timecode_show_hours;
1003 timecode_mark_modulo = 4;
1004 timecode_nmarks = 2 + 24;
1010 Editor::metric_get_timecode (GtkCustomRulerMark **marks, gdouble lower, gdouble /*upper*/, gint /*maxchars*/)
1014 Timecode::Time timecode;
1018 if (_session == 0) {
1022 if (lower > (spacer = (framecnt_t)(128 * Editor::get_current_zoom ()))) {
1023 lower = lower - spacer;
1028 pos = (framecnt_t) floor (lower);
1030 *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * timecode_nmarks);
1031 switch (timecode_ruler_scale) {
1032 case timecode_show_bits:
1034 // Find timecode time of this sample (pos) with subframe accuracy
1035 _session->sample_to_timecode(pos, timecode, true /* use_offset */, true /* use_subframes */ );
1037 for (n = 0; n < timecode_nmarks; n++) {
1038 _session->timecode_to_sample(timecode, pos, true /* use_offset */, true /* use_subframes */ );
1039 if ((timecode.subframes % timecode_mark_modulo) == 0) {
1040 if (timecode.subframes == 0) {
1041 (*marks)[n].style = GtkCustomRulerMarkMajor;
1042 snprintf (buf, sizeof(buf), "%s%02u:%02u:%02u:%02u", timecode.negative ? "-" : "", timecode.hours, timecode.minutes, timecode.seconds, timecode.frames);
1044 (*marks)[n].style = GtkCustomRulerMarkMinor;
1045 snprintf (buf, sizeof(buf), ".%02u", timecode.subframes);
1048 snprintf (buf, sizeof(buf)," ");
1049 (*marks)[n].style = GtkCustomRulerMarkMicro;
1052 (*marks)[n].label = g_strdup (buf);
1053 (*marks)[n].position = pos;
1055 // Increment subframes by one
1056 Timecode::increment_subframes( timecode, _session->config.get_subframes_per_frame() );
1059 case timecode_show_seconds:
1060 // Find timecode time of this sample (pos)
1061 _session->sample_to_timecode(pos, timecode, true /* use_offset */, false /* use_subframes */ );
1062 // Go to next whole second down
1063 Timecode::seconds_floor( timecode );
1065 for (n = 0; n < timecode_nmarks; n++) {
1066 _session->timecode_to_sample(timecode, pos, true /* use_offset */, false /* use_subframes */ );
1067 if ((timecode.seconds % timecode_mark_modulo) == 0) {
1068 if (timecode.seconds == 0) {
1069 (*marks)[n].style = GtkCustomRulerMarkMajor;
1070 (*marks)[n].position = pos;
1072 (*marks)[n].style = GtkCustomRulerMarkMinor;
1073 (*marks)[n].position = pos;
1075 snprintf (buf, sizeof(buf), "%s%02u:%02u:%02u:%02u", timecode.negative ? "-" : "", timecode.hours, timecode.minutes, timecode.seconds, timecode.frames);
1077 snprintf (buf, sizeof(buf)," ");
1078 (*marks)[n].style = GtkCustomRulerMarkMicro;
1079 (*marks)[n].position = pos;
1082 (*marks)[n].label = g_strdup (buf);
1083 Timecode::increment_seconds( timecode, _session->config.get_subframes_per_frame() );
1086 case timecode_show_minutes:
1087 // Find timecode time of this sample (pos)
1088 _session->sample_to_timecode(pos, timecode, true /* use_offset */, false /* use_subframes */ );
1089 // Go to next whole minute down
1090 Timecode::minutes_floor( timecode );
1092 for (n = 0; n < timecode_nmarks; n++) {
1093 _session->timecode_to_sample(timecode, pos, true /* use_offset */, false /* use_subframes */ );
1094 if ((timecode.minutes % timecode_mark_modulo) == 0) {
1095 if (timecode.minutes == 0) {
1096 (*marks)[n].style = GtkCustomRulerMarkMajor;
1098 (*marks)[n].style = GtkCustomRulerMarkMinor;
1100 snprintf (buf, sizeof(buf), "%s%02u:%02u:%02u:%02u", timecode.negative ? "-" : "", timecode.hours, timecode.minutes, timecode.seconds, timecode.frames);
1102 snprintf (buf, sizeof(buf)," ");
1103 (*marks)[n].style = GtkCustomRulerMarkMicro;
1106 (*marks)[n].label = g_strdup (buf);
1107 (*marks)[n].position = pos;
1109 Timecode::increment_minutes( timecode, _session->config.get_subframes_per_frame() );
1113 case timecode_show_hours:
1114 // Find timecode time of this sample (pos)
1115 _session->sample_to_timecode(pos, timecode, true /* use_offset */, false /* use_subframes */ );
1116 // Go to next whole hour down
1117 Timecode::hours_floor( timecode );
1119 for (n = 0; n < timecode_nmarks; n++) {
1120 _session->timecode_to_sample(timecode, pos, true /* use_offset */, false /* use_subframes */ );
1121 if ((timecode.hours % timecode_mark_modulo) == 0) {
1122 (*marks)[n].style = GtkCustomRulerMarkMajor;
1123 snprintf (buf, sizeof(buf), "%s%02u:%02u:%02u:%02u", timecode.negative ? "-" : "", timecode.hours, timecode.minutes, timecode.seconds, timecode.frames);
1125 snprintf (buf, sizeof(buf)," ");
1126 (*marks)[n].style = GtkCustomRulerMarkMicro;
1129 (*marks)[n].label = g_strdup (buf);
1130 (*marks)[n].position = pos;
1132 Timecode::increment_hours( timecode, _session->config.get_subframes_per_frame() );
1135 case timecode_show_frames:
1136 // Find timecode time of this sample (pos)
1137 _session->sample_to_timecode(pos, timecode, true /* use_offset */, false /* use_subframes */ );
1138 // Go to next whole frame down
1139 Timecode::frames_floor( timecode );
1141 for (n = 0; n < timecode_nmarks; n++) {
1142 _session->timecode_to_sample(timecode, pos, true /* use_offset */, false /* use_subframes */ );
1143 if ((timecode.frames % timecode_mark_modulo) == 0) {
1144 if (timecode.frames == 0) {
1145 (*marks)[n].style = GtkCustomRulerMarkMajor;
1147 (*marks)[n].style = GtkCustomRulerMarkMinor;
1149 (*marks)[n].position = pos;
1150 snprintf (buf, sizeof(buf), "%s%02u:%02u:%02u:%02u", timecode.negative ? "-" : "", timecode.hours, timecode.minutes, timecode.seconds, timecode.frames);
1152 snprintf (buf, sizeof(buf)," ");
1153 (*marks)[n].style = GtkCustomRulerMarkMicro;
1154 (*marks)[n].position = pos;
1157 (*marks)[n].label = g_strdup (buf);
1158 Timecode::increment( timecode, _session->config.get_subframes_per_frame() );
1164 return timecode_nmarks;
1169 Editor::compute_bbt_ruler_scale (framepos_t lower, framepos_t upper,
1170 ARDOUR::TempoMap::BBTPointList::const_iterator begin,
1171 ARDOUR::TempoMap::BBTPointList::const_iterator end)
1173 if (_session == 0) {
1177 TempoMap::BBTPointList::const_iterator i;
1178 Timecode::BBT_Time lower_beat, upper_beat; // the beats at each end of the ruler
1180 _session->bbt_time (lower, lower_beat);
1181 _session->bbt_time (upper, upper_beat);
1184 bbt_accent_modulo = 1;
1185 bbt_bar_helper_on = false;
1189 bbt_ruler_scale = bbt_over;
1191 switch (_snap_type) {
1192 case SnapToBeatDiv2:
1193 bbt_beat_subdivision = 2;
1195 case SnapToBeatDiv3:
1196 bbt_beat_subdivision = 3;
1198 case SnapToBeatDiv4:
1199 bbt_beat_subdivision = 4;
1201 case SnapToBeatDiv5:
1202 bbt_beat_subdivision = 5;
1203 bbt_accent_modulo = 2; // XXX YIKES
1205 case SnapToBeatDiv6:
1206 bbt_beat_subdivision = 6;
1207 bbt_accent_modulo = 2; // XXX YIKES
1209 case SnapToBeatDiv7:
1210 bbt_beat_subdivision = 7;
1211 bbt_accent_modulo = 2; // XXX YIKES
1213 case SnapToBeatDiv8:
1214 bbt_beat_subdivision = 8;
1215 bbt_accent_modulo = 2;
1217 case SnapToBeatDiv10:
1218 bbt_beat_subdivision = 10;
1219 bbt_accent_modulo = 2; // XXX YIKES
1221 case SnapToBeatDiv12:
1222 bbt_beat_subdivision = 12;
1223 bbt_accent_modulo = 3;
1225 case SnapToBeatDiv14:
1226 bbt_beat_subdivision = 14;
1227 bbt_accent_modulo = 3; // XXX YIKES!
1229 case SnapToBeatDiv16:
1230 bbt_beat_subdivision = 16;
1231 bbt_accent_modulo = 4;
1233 case SnapToBeatDiv20:
1234 bbt_beat_subdivision = 20;
1235 bbt_accent_modulo = 5;
1237 case SnapToBeatDiv24:
1238 bbt_beat_subdivision = 24;
1239 bbt_accent_modulo = 6;
1241 case SnapToBeatDiv28:
1242 bbt_beat_subdivision = 28;
1243 bbt_accent_modulo = 7;
1245 case SnapToBeatDiv32:
1246 bbt_beat_subdivision = 32;
1247 bbt_accent_modulo = 8;
1249 case SnapToBeatDiv64:
1250 bbt_beat_subdivision = 64;
1251 bbt_accent_modulo = 8;
1253 case SnapToBeatDiv128:
1254 bbt_beat_subdivision = 128;
1255 bbt_accent_modulo = 8;
1258 bbt_beat_subdivision = 4;
1262 if (distance (begin, end) == 0) {
1268 if ((*i).beat >= (*begin).beat) {
1269 bbt_bars = (*i).bar - (*begin).bar;
1271 bbt_bars = (*i).bar - (*begin).bar - 1;
1273 beats = distance (begin, end) - bbt_bars;
1275 /* Only show the bar helper if there aren't many bars on the screen */
1276 if ((bbt_bars < 2) || (beats < 5)) {
1277 bbt_bar_helper_on = true;
1280 if (bbt_bars > 8192) {
1281 bbt_ruler_scale = bbt_over;
1282 } else if (bbt_bars > 1024) {
1283 bbt_ruler_scale = bbt_show_64;
1284 } else if (bbt_bars > 256) {
1285 bbt_ruler_scale = bbt_show_16;
1286 } else if (bbt_bars > 64) {
1287 bbt_ruler_scale = bbt_show_4;
1288 } else if (bbt_bars > 10) {
1289 bbt_ruler_scale = bbt_show_1;
1290 } else if (bbt_bars > 2) {
1291 bbt_ruler_scale = bbt_show_beats;
1292 } else if (bbt_bars > 0) {
1293 bbt_ruler_scale = bbt_show_ticks;
1295 bbt_ruler_scale = bbt_show_ticks_detail;
1298 if ((bbt_ruler_scale == bbt_show_ticks_detail) && (lower_beat.beats == upper_beat.beats) && (upper_beat.ticks - lower_beat.ticks <= Timecode::BBT_Time::ticks_per_beat / 4)) {
1299 bbt_ruler_scale = bbt_show_ticks_super_detail;
1304 Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble upper, gint /*maxchars*/)
1306 if (_session == 0) {
1310 TempoMap::BBTPointList::const_iterator i;
1315 Timecode::BBT_Time next_beat;
1316 framepos_t next_beat_pos;
1322 framepos_t frame_skip;
1323 double frame_skip_error;
1324 double bbt_position_of_helper;
1325 double accumulated_error;
1326 bool i_am_accented = false;
1327 bool helper_active = false;
1329 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
1330 ARDOUR::TempoMap::BBTPointList::const_iterator end;
1332 compute_current_bbt_points (lower, upper, begin, end);
1334 if (distance (begin, end) == 0) {
1338 switch (bbt_ruler_scale) {
1340 case bbt_show_beats:
1341 beats = distance (begin, end);
1342 bbt_nmarks = beats + 2;
1344 *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks);
1346 (*marks)[0].label = g_strdup(" ");
1347 (*marks)[0].position = lower;
1348 (*marks)[0].style = GtkCustomRulerMarkMicro;
1350 for (n = 1, i = begin; n < bbt_nmarks && i != end; ++i) {
1352 if ((*i).frame < lower && (bbt_bar_helper_on)) {
1353 snprintf (buf, sizeof(buf), "<%" PRIu32 "|%" PRIu32, (*i).bar, (*i).beat);
1354 (*marks)[0].label = g_strdup (buf);
1355 helper_active = true;
1358 if ((*i).is_bar()) {
1359 (*marks)[n].style = GtkCustomRulerMarkMajor;
1360 snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar);
1361 } else if (((*i).beat % 2 == 1)) {
1362 (*marks)[n].style = GtkCustomRulerMarkMinor;
1363 snprintf (buf, sizeof(buf), " ");
1365 (*marks)[n].style = GtkCustomRulerMarkMicro;
1366 snprintf (buf, sizeof(buf), " ");
1368 (*marks)[n].label = g_strdup (buf);
1369 (*marks)[n].position = (*i).frame;
1375 case bbt_show_ticks:
1377 beats = distance (begin, end);
1378 bbt_nmarks = (beats + 2) * bbt_beat_subdivision;
1380 bbt_position_of_helper = lower + (30 * Editor::get_current_zoom ());
1381 *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks);
1383 (*marks)[0].label = g_strdup(" ");
1384 (*marks)[0].position = lower;
1385 (*marks)[0].style = GtkCustomRulerMarkMicro;
1387 for (n = 1, i = begin; n < bbt_nmarks && i != end; ++i) {
1389 if ((*i).frame < lower && (bbt_bar_helper_on)) {
1390 snprintf (buf, sizeof(buf), "<%" PRIu32 "|%" PRIu32, (*i).bar, (*i).beat);
1391 (*marks)[0].label = g_strdup (buf);
1392 helper_active = true;
1395 if ((*i).is_bar()) {
1396 (*marks)[n].style = GtkCustomRulerMarkMajor;
1397 snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar);
1399 (*marks)[n].style = GtkCustomRulerMarkMinor;
1400 snprintf (buf, sizeof(buf), "%" PRIu32, (*i).beat);
1402 if (((*i).frame < bbt_position_of_helper) && helper_active) {
1403 snprintf (buf, sizeof(buf), " ");
1405 (*marks)[n].label = g_strdup (buf);
1406 (*marks)[n].position = (*i).frame;
1410 /* Add the tick marks */
1412 /* Find the next beat */
1413 next_beat.beats = (*i).beat;
1414 next_beat.bars = (*i).bar;
1415 next_beat.ticks = 0;
1417 if ((*i).meter->divisions_per_bar() > (next_beat.beats + 1)) {
1418 next_beat.beats += 1;
1420 next_beat.bars += 1;
1421 next_beat.beats = 1;
1424 next_beat_pos = _session->tempo_map().frame_time(next_beat);
1426 frame_skip = (framepos_t) floor (frame_skip_error = (_session->frame_rate() * 60) / (bbt_beat_subdivision * (*i).tempo->beats_per_minute()));
1427 frame_skip_error -= frame_skip;
1428 skip = (uint32_t) (Timecode::BBT_Time::ticks_per_beat / bbt_beat_subdivision);
1430 pos = (*i).frame + frame_skip;
1431 accumulated_error = frame_skip_error;
1435 for (t = 0; (tick < Timecode::BBT_Time::ticks_per_beat) && (n < bbt_nmarks) && (pos < next_beat_pos) ; pos += frame_skip, tick += skip, ++t) {
1437 if (t % bbt_accent_modulo == (bbt_accent_modulo - 1)) {
1438 i_am_accented = true;
1441 snprintf (buf, sizeof(buf), " ");
1442 (*marks)[n].label = g_strdup (buf);
1444 /* Error compensation for float to framepos_t*/
1445 accumulated_error += frame_skip_error;
1446 if (accumulated_error > 1) {
1448 accumulated_error -= 1.0f;
1451 (*marks)[n].position = pos;
1453 if ((bbt_beat_subdivision > 4) && i_am_accented) {
1454 (*marks)[n].style = GtkCustomRulerMarkMinor;
1456 (*marks)[n].style = GtkCustomRulerMarkMicro;
1458 i_am_accented = false;
1465 case bbt_show_ticks_detail:
1467 beats = distance (begin, end);
1468 bbt_nmarks = (beats + 2) * bbt_beat_subdivision;
1470 bbt_position_of_helper = lower + (30 * Editor::get_current_zoom ());
1471 *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks);
1473 (*marks)[0].label = g_strdup(" ");
1474 (*marks)[0].position = lower;
1475 (*marks)[0].style = GtkCustomRulerMarkMicro;
1477 for (n = 1, i = begin; n < bbt_nmarks && i != end; ++i) {
1479 if ((*i).frame < lower && (bbt_bar_helper_on)) {
1480 snprintf (buf, sizeof(buf), "<%" PRIu32 "|%" PRIu32, (*i).bar, (*i).beat);
1481 (*marks)[0].label = g_strdup (buf);
1482 helper_active = true;
1485 if ((*i).is_bar()) {
1486 (*marks)[n].style = GtkCustomRulerMarkMajor;
1487 snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar);
1489 (*marks)[n].style = GtkCustomRulerMarkMinor;
1490 snprintf (buf, sizeof(buf), "%" PRIu32, (*i).beat);
1492 if (((*i).frame < bbt_position_of_helper) && helper_active) {
1493 snprintf (buf, sizeof(buf), " ");
1495 (*marks)[n].label = g_strdup (buf);
1496 (*marks)[n].position = (*i).frame;
1500 /* Add the tick marks */
1502 /* Find the next beat */
1504 next_beat.beats = (*i).beat;
1505 next_beat.bars = (*i).bar;
1507 if ((*i).meter->divisions_per_bar() > (next_beat.beats + 1)) {
1508 next_beat.beats += 1;
1510 next_beat.bars += 1;
1511 next_beat.beats = 1;
1514 next_beat_pos = _session->tempo_map().frame_time(next_beat);
1516 frame_skip = (framepos_t) floor (frame_skip_error = (_session->frame_rate() * 60) / (bbt_beat_subdivision * (*i).tempo->beats_per_minute()));
1517 frame_skip_error -= frame_skip;
1518 skip = (uint32_t) (Timecode::BBT_Time::ticks_per_beat / bbt_beat_subdivision);
1520 pos = (*i).frame + frame_skip;
1521 accumulated_error = frame_skip_error;
1525 for (t = 0; (tick < Timecode::BBT_Time::ticks_per_beat) && (n < bbt_nmarks) && (pos < next_beat_pos) ; pos += frame_skip, tick += skip, ++t) {
1527 if (t % bbt_accent_modulo == (bbt_accent_modulo - 1)) {
1528 i_am_accented = true;
1531 if (i_am_accented && (pos > bbt_position_of_helper)){
1532 snprintf (buf, sizeof(buf), "%" PRIu32, tick);
1534 snprintf (buf, sizeof(buf), " ");
1537 (*marks)[n].label = g_strdup (buf);
1539 /* Error compensation for float to framepos_t*/
1540 accumulated_error += frame_skip_error;
1541 if (accumulated_error > 1) {
1543 accumulated_error -= 1.0f;
1546 (*marks)[n].position = pos;
1548 if ((bbt_beat_subdivision > 4) && i_am_accented) {
1549 (*marks)[n].style = GtkCustomRulerMarkMinor;
1551 (*marks)[n].style = GtkCustomRulerMarkMicro;
1553 i_am_accented = false;
1560 case bbt_show_ticks_super_detail:
1562 beats = distance (begin, end);
1563 bbt_nmarks = (beats + 2) * bbt_beat_subdivision;
1565 bbt_position_of_helper = lower + (30 * Editor::get_current_zoom ());
1566 *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks);
1568 (*marks)[0].label = g_strdup(" ");
1569 (*marks)[0].position = lower;
1570 (*marks)[0].style = GtkCustomRulerMarkMicro;
1572 for (n = 1, i = begin; n < bbt_nmarks && i != end; ++i) {
1574 if ((*i).frame < lower && (bbt_bar_helper_on)) {
1575 snprintf (buf, sizeof(buf), "<%" PRIu32 "|%" PRIu32, (*i).bar, (*i).beat);
1576 (*marks)[0].label = g_strdup (buf);
1577 helper_active = true;
1580 if ((*i).is_bar()) {
1581 (*marks)[n].style = GtkCustomRulerMarkMajor;
1582 snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar);
1584 (*marks)[n].style = GtkCustomRulerMarkMinor;
1585 snprintf (buf, sizeof(buf), "%" PRIu32, (*i).beat);
1587 if (((*i).frame < bbt_position_of_helper) && helper_active) {
1588 snprintf (buf, sizeof(buf), " ");
1590 (*marks)[n].label = g_strdup (buf);
1591 (*marks)[n].position = (*i).frame;
1595 /* Add the tick marks */
1597 /* Find the next beat */
1599 next_beat.beats = (*i).beat;
1600 next_beat.bars = (*i).bar;
1602 if ((*i).meter->divisions_per_bar() > (next_beat.beats + 1)) {
1603 next_beat.beats += 1;
1605 next_beat.bars += 1;
1606 next_beat.beats = 1;
1609 next_beat_pos = _session->tempo_map().frame_time(next_beat);
1611 frame_skip = (framepos_t) floor (frame_skip_error = (_session->frame_rate() * 60) / (bbt_beat_subdivision * (*i).tempo->beats_per_minute()));
1612 frame_skip_error -= frame_skip;
1613 skip = (uint32_t) (Timecode::BBT_Time::ticks_per_beat / bbt_beat_subdivision);
1615 pos = (*i).frame + frame_skip;
1616 accumulated_error = frame_skip_error;
1620 for (t = 0; (tick < Timecode::BBT_Time::ticks_per_beat) && (n < bbt_nmarks) && (pos < next_beat_pos) ; pos += frame_skip, tick += skip, ++t) {
1622 if (t % bbt_accent_modulo == (bbt_accent_modulo - 1)) {
1623 i_am_accented = true;
1626 if (pos > bbt_position_of_helper) {
1627 snprintf (buf, sizeof(buf), "%" PRIu32, tick);
1629 snprintf (buf, sizeof(buf), " ");
1632 (*marks)[n].label = g_strdup (buf);
1634 /* Error compensation for float to framepos_t*/
1635 accumulated_error += frame_skip_error;
1636 if (accumulated_error > 1) {
1638 accumulated_error -= 1.0f;
1641 (*marks)[n].position = pos;
1643 if ((bbt_beat_subdivision > 4) && i_am_accented) {
1644 (*marks)[n].style = GtkCustomRulerMarkMinor;
1646 (*marks)[n].style = GtkCustomRulerMarkMicro;
1648 i_am_accented = false;
1657 *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks);
1658 snprintf (buf, sizeof(buf), "cannot handle %" PRIu32 " bars", bbt_bars );
1659 (*marks)[0].style = GtkCustomRulerMarkMajor;
1660 (*marks)[0].label = g_strdup (buf);
1661 (*marks)[0].position = lower;
1667 bbt_nmarks = (gint) (bbt_bars / 64) + 1;
1668 *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks);
1669 for (n = 0, i = begin; i != end && n < bbt_nmarks; i++) {
1670 if ((*i).is_bar()) {
1671 if ((*i).bar % 64 == 1) {
1672 if ((*i).bar % 256 == 1) {
1673 snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar);
1674 (*marks)[n].style = GtkCustomRulerMarkMajor;
1676 snprintf (buf, sizeof(buf), " ");
1677 if ((*i).bar % 256 == 129) {
1678 (*marks)[n].style = GtkCustomRulerMarkMinor;
1680 (*marks)[n].style = GtkCustomRulerMarkMicro;
1683 (*marks)[n].label = g_strdup (buf);
1684 (*marks)[n].position = (*i).frame;
1692 bbt_nmarks = (bbt_bars / 16) + 1;
1693 *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks);
1694 for (n = 0, i = begin; i != end && n < bbt_nmarks; i++) {
1695 if ((*i).is_bar()) {
1696 if ((*i).bar % 16 == 1) {
1697 if ((*i).bar % 64 == 1) {
1698 snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar);
1699 (*marks)[n].style = GtkCustomRulerMarkMajor;
1701 snprintf (buf, sizeof(buf), " ");
1702 if ((*i).bar % 64 == 33) {
1703 (*marks)[n].style = GtkCustomRulerMarkMinor;
1705 (*marks)[n].style = GtkCustomRulerMarkMicro;
1708 (*marks)[n].label = g_strdup (buf);
1709 (*marks)[n].position = (*i).frame;
1717 bbt_nmarks = (bbt_bars / 4) + 1;
1718 *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks);
1719 for (n = 0, i = begin; i != end && n < bbt_nmarks; ++i) {
1720 if ((*i).is_bar()) {
1721 if ((*i).bar % 4 == 1) {
1722 if ((*i).bar % 16 == 1) {
1723 snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar);
1724 (*marks)[n].style = GtkCustomRulerMarkMajor;
1726 snprintf (buf, sizeof(buf), " ");
1727 if ((*i).bar % 16 == 9) {
1728 (*marks)[n].style = GtkCustomRulerMarkMinor;
1730 (*marks)[n].style = GtkCustomRulerMarkMicro;
1733 (*marks)[n].label = g_strdup (buf);
1734 (*marks)[n].position = (*i).frame;
1743 bbt_nmarks = bbt_bars + 2;
1744 *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks );
1745 for (n = 0, i = begin; i != end && n < bbt_nmarks; i++) {
1746 if ((*i).is_bar()) {
1747 if ((*i).bar % 4 == 1) {
1748 snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar);
1749 (*marks)[n].style = GtkCustomRulerMarkMajor;
1751 snprintf (buf, sizeof(buf), " ");
1752 if ((*i).bar % 4 == 3) {
1753 (*marks)[n].style = GtkCustomRulerMarkMinor;
1755 (*marks)[n].style = GtkCustomRulerMarkMicro;
1758 (*marks)[n].label = g_strdup (buf);
1759 (*marks)[n].position = (*i).frame;
1768 return n; //return the actual number of marks made, since we might have skipped some from fractional time signatures
1773 Editor::set_samples_ruler_scale (framepos_t lower, framepos_t upper)
1775 _samples_ruler_interval = (upper - lower) / 5;
1779 Editor::metric_get_samples (GtkCustomRulerMark **marks, gdouble lower, gdouble /*upper*/, gint /*maxchars*/)
1782 framepos_t const ilower = (framepos_t) floor (lower);
1787 if (_session == 0) {
1792 *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks);
1793 for (n = 0, pos = ilower; n < nmarks; pos += _samples_ruler_interval, ++n) {
1794 snprintf (buf, sizeof(buf), "%" PRIi64, pos);
1795 (*marks)[n].label = g_strdup (buf);
1796 (*marks)[n].position = pos;
1797 (*marks)[n].style = GtkCustomRulerMarkMajor;
1804 sample_to_clock_parts ( framepos_t sample,
1805 framepos_t sample_rate,
1819 hrs = left / (sample_rate * 60 * 60 * 1000);
1820 left -= hrs * sample_rate * 60 * 60 * 1000;
1821 mins = left / (sample_rate * 60 * 1000);
1822 left -= mins * sample_rate * 60 * 1000;
1823 secs = left / (sample_rate * 1000);
1824 left -= secs * sample_rate * 1000;
1825 millisecs = left / sample_rate;
1827 *millisecs_p = millisecs;
1836 Editor::set_minsec_ruler_scale (framepos_t lower, framepos_t upper)
1841 if (_session == 0) {
1845 fr = _session->frame_rate() * 1000;
1847 /* to prevent 'flashing' */
1848 if (lower > (spacer = (framepos_t)(128 * Editor::get_current_zoom ()))) {
1854 framecnt_t const range = (upper - lower) * 1000;
1856 if (range < (fr / 50)) {
1857 minsec_mark_interval = fr / 1000; /* show 1/1000 seconds */
1858 minsec_ruler_scale = minsec_show_frames;
1859 minsec_mark_modulo = 10;
1860 } else if (range <= (fr / 10)) { /* 0-0.1 second */
1861 minsec_mark_interval = fr / 1000; /* show 1/1000 seconds */
1862 minsec_ruler_scale = minsec_show_frames;
1863 minsec_mark_modulo = 10;
1864 } else if (range <= (fr / 2)) { /* 0-0.5 second */
1865 minsec_mark_interval = fr / 100; /* show 1/100 seconds */
1866 minsec_ruler_scale = minsec_show_frames;
1867 minsec_mark_modulo = 100;
1868 } else if (range <= fr) { /* 0-1 second */
1869 minsec_mark_interval = fr / 10; /* show 1/10 seconds */
1870 minsec_ruler_scale = minsec_show_frames;
1871 minsec_mark_modulo = 200;
1872 } else if (range <= 2 * fr) { /* 1-2 seconds */
1873 minsec_mark_interval = fr / 10; /* show 1/10 seconds */
1874 minsec_ruler_scale = minsec_show_frames;
1875 minsec_mark_modulo = 500;
1876 } else if (range <= 8 * fr) { /* 2-5 seconds */
1877 minsec_mark_interval = fr / 5; /* show 2 seconds */
1878 minsec_ruler_scale = minsec_show_frames;
1879 minsec_mark_modulo = 1000;
1880 } else if (range <= 16 * fr) { /* 8-16 seconds */
1881 minsec_mark_interval = fr; /* show 1 seconds */
1882 minsec_ruler_scale = minsec_show_seconds;
1883 minsec_mark_modulo = 2;
1884 } else if (range <= 30 * fr) { /* 10-30 seconds */
1885 minsec_mark_interval = fr; /* show 1 seconds */
1886 minsec_ruler_scale = minsec_show_seconds;
1887 minsec_mark_modulo = 5;
1888 } else if (range <= 60 * fr) { /* 30-60 seconds */
1889 minsec_mark_interval = fr; /* show 1 seconds */
1890 minsec_ruler_scale = minsec_show_seconds;
1891 minsec_mark_modulo = 5;
1892 } else if (range <= 2 * 60 * fr) { /* 1-2 minutes */
1893 minsec_mark_interval = 5 * fr; /* show 5 seconds */
1894 minsec_ruler_scale = minsec_show_seconds;
1895 minsec_mark_modulo = 3;
1896 } else if (range <= 4 * 60 * fr) { /* 4 minutes */
1897 minsec_mark_interval = 5 * fr; /* show 10 seconds */
1898 minsec_ruler_scale = minsec_show_seconds;
1899 minsec_mark_modulo = 30;
1900 } else if (range <= 10 * 60 * fr) { /* 10 minutes */
1901 minsec_mark_interval = 30 * fr; /* show 30 seconds */
1902 minsec_ruler_scale = minsec_show_seconds;
1903 minsec_mark_modulo = 120;
1904 } else if (range <= 30 * 60 * fr) { /* 10-30 minutes */
1905 minsec_mark_interval = 60 * fr; /* show 1 minute */
1906 minsec_ruler_scale = minsec_show_minutes;
1907 minsec_mark_modulo = 5;
1908 } else if (range <= 60 * 60 * fr) { /* 30 minutes - 1hr */
1909 minsec_mark_interval = 2 * 60 * fr; /* show 2 minutes */
1910 minsec_ruler_scale = minsec_show_minutes;
1911 minsec_mark_modulo = 10;
1912 } else if (range <= 4 * 60 * 60 * fr) { /* 1 - 4 hrs*/
1913 minsec_mark_interval = 5 * 60 * fr; /* show 10 minutes */
1914 minsec_ruler_scale = minsec_show_minutes;
1915 minsec_mark_modulo = 30;
1916 } else if (range <= 8 * 60 * 60 * fr) { /* 4 - 8 hrs*/
1917 minsec_mark_interval = 20 * 60 * fr; /* show 20 minutes */
1918 minsec_ruler_scale = minsec_show_minutes;
1919 minsec_mark_modulo = 60;
1920 } else if (range <= 16 * 60 * 60 * fr) { /* 16-24 hrs*/
1921 minsec_mark_interval = 60 * 60 * fr; /* show 60 minutes */
1922 minsec_ruler_scale = minsec_show_hours;
1923 minsec_mark_modulo = 2;
1926 /* not possible if framepos_t is a 32 bit quantity */
1928 minsec_mark_interval = 4 * 60 * 60 * fr; /* show 4 hrs */
1930 minsec_nmarks = 2 + (range / minsec_mark_interval);
1934 Editor::metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble /*upper*/, gint /*maxchars*/)
1938 long hrs, mins, secs, millisecs;
1942 if (_session == 0) {
1946 /* to prevent 'flashing' */
1947 if (lower > (spacer = (framepos_t) (128 * Editor::get_current_zoom ()))) {
1948 lower = lower - spacer;
1953 *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * minsec_nmarks);
1954 pos = (((1000 * (framepos_t) floor(lower)) + (minsec_mark_interval/2))/minsec_mark_interval) * minsec_mark_interval;
1955 switch (minsec_ruler_scale) {
1956 case minsec_show_seconds:
1957 for (n = 0; n < minsec_nmarks; pos += minsec_mark_interval, ++n) {
1958 sample_to_clock_parts (pos, _session->frame_rate(), &hrs, &mins, &secs, &millisecs);
1959 if (secs % minsec_mark_modulo == 0) {
1961 (*marks)[n].style = GtkCustomRulerMarkMajor;
1963 (*marks)[n].style = GtkCustomRulerMarkMinor;
1965 snprintf (buf, sizeof(buf), "%02ld:%02ld:%02ld.%03ld", hrs, mins, secs, millisecs);
1967 snprintf (buf, sizeof(buf), " ");
1968 (*marks)[n].style = GtkCustomRulerMarkMicro;
1970 (*marks)[n].label = g_strdup (buf);
1971 (*marks)[n].position = pos/1000.0;
1974 case minsec_show_minutes:
1975 for (n = 0; n < minsec_nmarks; pos += minsec_mark_interval, ++n) {
1976 sample_to_clock_parts (pos, _session->frame_rate(), &hrs, &mins, &secs, &millisecs);
1977 if (mins % minsec_mark_modulo == 0) {
1979 (*marks)[n].style = GtkCustomRulerMarkMajor;
1981 (*marks)[n].style = GtkCustomRulerMarkMinor;
1983 snprintf (buf, sizeof(buf), "%02ld:%02ld:%02ld.%03ld", hrs, mins, secs, millisecs);
1985 snprintf (buf, sizeof(buf), " ");
1986 (*marks)[n].style = GtkCustomRulerMarkMicro;
1988 (*marks)[n].label = g_strdup (buf);
1989 (*marks)[n].position = pos/1000.0;
1992 case minsec_show_hours:
1993 for (n = 0; n < minsec_nmarks; pos += minsec_mark_interval, ++n) {
1994 sample_to_clock_parts (pos, _session->frame_rate(), &hrs, &mins, &secs, &millisecs);
1995 if (hrs % minsec_mark_modulo == 0) {
1996 (*marks)[n].style = GtkCustomRulerMarkMajor;
1997 snprintf (buf, sizeof(buf), "%02ld:%02ld:%02ld.%03ld", hrs, mins, secs, millisecs);
1999 snprintf (buf, sizeof(buf), " ");
2000 (*marks)[n].style = GtkCustomRulerMarkMicro;
2002 (*marks)[n].label = g_strdup (buf);
2003 (*marks)[n].position = pos/1000.0;
2006 case minsec_show_frames:
2007 for (n = 0; n < minsec_nmarks; pos += minsec_mark_interval, ++n) {
2008 sample_to_clock_parts (pos, _session->frame_rate(), &hrs, &mins, &secs, &millisecs);
2009 if (millisecs % minsec_mark_modulo == 0) {
2010 if (millisecs == 0) {
2011 (*marks)[n].style = GtkCustomRulerMarkMajor;
2013 (*marks)[n].style = GtkCustomRulerMarkMinor;
2015 snprintf (buf, sizeof(buf), "%02ld:%02ld:%02ld.%03ld", hrs, mins, secs, millisecs);
2017 snprintf (buf, sizeof(buf), " ");
2018 (*marks)[n].style = GtkCustomRulerMarkMicro;
2020 (*marks)[n].label = g_strdup (buf);
2021 (*marks)[n].position = pos/1000.0;
2026 return minsec_nmarks;