centre gain meter display, some bbt ruler fixes
[ardour.git] / gtk2_ardour / editor_rulers.cc
1 /*
2     Copyright (C) 2000 Paul Davis 
3
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.
8
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.
13
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.
17
18     $Id$
19 */
20
21 #include <cstdio> // for sprintf, grrr 
22 #include <cmath>
23
24 #include <string>
25
26 #include <ardour/tempo.h>
27 #include <gtkmm2ext/gtk_ui.h>
28
29 #include "editor.h"
30 #include "editing.h"
31 #include "gtk-custom-hruler.h"
32 #include "gui_thread.h"
33
34 #include "i18n.h"
35
36 using namespace sigc;
37 using namespace ARDOUR;
38 using namespace PBD;
39 using namespace Gtk;
40 using namespace Editing;
41
42 Editor *Editor::ruler_editor;
43
44 /* the order here must match the "metric" enums in editor.h */
45
46 GtkCustomMetric Editor::ruler_metrics[4] = {
47         {1, Editor::_metric_get_smpte },
48         {1, Editor::_metric_get_bbt },
49         {1, Editor::_metric_get_frames },
50         {1, Editor::_metric_get_minsec }
51 };
52
53 void
54 Editor::initialize_rulers ()
55 {
56         ruler_editor = this;
57         ruler_grabbed_widget = 0;
58         
59         _smpte_ruler = gtk_custom_hruler_new ();
60         smpte_ruler = Glib::wrap (_smpte_ruler);
61         smpte_ruler->set_name ("SMPTERuler");
62         smpte_ruler->set_size_request (-1, (int)timebar_height);
63         gtk_custom_ruler_set_metric (GTK_CUSTOM_RULER(_smpte_ruler), &ruler_metrics[ruler_metric_smpte]);
64         ruler_shown[ruler_metric_smpte] = true;
65         
66         _bbt_ruler = gtk_custom_hruler_new ();
67         bbt_ruler = Glib::wrap (_bbt_ruler);
68         bbt_ruler->set_name ("BBTRuler");
69         bbt_ruler->set_size_request (-1, (int)timebar_height);
70         gtk_custom_ruler_set_metric (GTK_CUSTOM_RULER(_bbt_ruler), &ruler_metrics[ruler_metric_bbt]);
71         ruler_shown[ruler_metric_bbt] = true;
72
73         _frames_ruler = gtk_custom_hruler_new ();
74         frames_ruler = Glib::wrap (_frames_ruler);
75         frames_ruler->set_name ("FramesRuler");
76         frames_ruler->set_size_request (-1, (int)timebar_height);
77         gtk_custom_ruler_set_metric (GTK_CUSTOM_RULER(_frames_ruler), &ruler_metrics[ruler_metric_frames]);
78
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
85         ruler_shown[ruler_time_meter] = true;
86         ruler_shown[ruler_time_tempo] = true;
87         ruler_shown[ruler_time_marker] = true;
88         ruler_shown[ruler_time_range_marker] = true;
89         ruler_shown[ruler_time_transport_marker] = true;
90         ruler_shown[ruler_metric_frames] = false;
91         ruler_shown[ruler_metric_minsec] = false;
92         
93         smpte_ruler->set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
94         bbt_ruler->set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
95         frames_ruler->set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
96         minsec_ruler->set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
97
98         smpte_ruler->signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_button_release));
99         bbt_ruler->signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_button_release));
100         frames_ruler->signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_button_release));
101         minsec_ruler->signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_button_release));
102
103         smpte_ruler->signal_button_press_event().connect (mem_fun(*this, &Editor::ruler_button_press));
104         bbt_ruler->signal_button_press_event().connect (mem_fun(*this, &Editor::ruler_button_press));
105         frames_ruler->signal_button_press_event().connect (mem_fun(*this, &Editor::ruler_button_press));
106         minsec_ruler->signal_button_press_event().connect (mem_fun(*this, &Editor::ruler_button_press));
107         
108         smpte_ruler->signal_motion_notify_event().connect (mem_fun(*this, &Editor::ruler_mouse_motion));
109         bbt_ruler->signal_motion_notify_event().connect (mem_fun(*this, &Editor::ruler_mouse_motion));
110         frames_ruler->signal_motion_notify_event().connect (mem_fun(*this, &Editor::ruler_mouse_motion));
111         minsec_ruler->signal_motion_notify_event().connect (mem_fun(*this, &Editor::ruler_mouse_motion));
112         
113         visible_timebars = 7; /* 4 here, 3 in time_canvas */
114         ruler_pressed_button = 0;
115 }
116
117
118 gint
119 Editor::ruler_button_press (GdkEventButton* ev)
120 {
121         if (session == 0) {
122                 return FALSE;
123         }
124
125         ruler_pressed_button = ev->button;
126
127         // jlc: grab ev->window ?
128         //Gtk::Main::grab_add (*minsec_ruler);
129         Widget * grab_widget = 0;
130
131         if (smpte_ruler->is_realized() && ev->window == smpte_ruler->get_window()->gobj()) grab_widget = smpte_ruler;
132         else if (bbt_ruler->is_realized() && ev->window == bbt_ruler->get_window()->gobj()) grab_widget = bbt_ruler;
133         else if (frames_ruler->is_realized() && ev->window == frames_ruler->get_window()->gobj()) grab_widget = frames_ruler;
134         else if (minsec_ruler->is_realized() && ev->window == minsec_ruler->get_window()->gobj()) grab_widget = minsec_ruler;
135
136         if (grab_widget) {
137                 grab_widget->add_modal_grab ();
138                 ruler_grabbed_widget = grab_widget;
139         }
140
141         return TRUE;
142 }
143
144 gint
145 Editor::ruler_button_release (GdkEventButton* ev)
146 {
147         gint x,y;
148         Gdk::ModifierType state;
149
150         /* need to use the correct x,y, the event lies */
151         time_canvas_event_box.get_window()->get_pointer (x, y, state);
152
153
154         ruler_pressed_button = 0;
155         
156         if (session == 0) {
157                 return FALSE;
158         }
159
160         hide_verbose_canvas_cursor();
161         stop_canvas_autoscroll();
162         
163         nframes_t where = leftmost_frame + pixel_to_frame (x);
164
165         switch (ev->button) {
166         case 1:
167                 /* transport playhead */
168                 snap_to (where);
169                 session->request_locate (where);
170                 break;
171
172         case 2:
173                 /* edit cursor */
174                 if (snap_type != Editing::SnapToEditCursor) {
175                         snap_to (where);
176                 }
177                 edit_cursor->set_position (where);
178                 edit_cursor_clock.set (where);
179                 break;
180
181         case 3:
182                 /* popup menu */
183                 snap_to (where);
184                 popup_ruler_menu (where);
185                 
186                 break;
187         default:
188                 break;
189         }
190
191
192         if (ruler_grabbed_widget) {
193                 ruler_grabbed_widget->remove_modal_grab();
194                 ruler_grabbed_widget = 0;
195         }
196
197         return TRUE;
198 }
199
200 gint
201 Editor::ruler_label_button_release (GdkEventButton* ev)
202 {
203         if (ev->button == 3)
204         {
205                 popup_ruler_menu();
206         }
207         
208         return TRUE;
209 }
210
211
212 gint
213 Editor::ruler_mouse_motion (GdkEventMotion* ev)
214 {
215         if (session == 0 || !ruler_pressed_button) {
216                 return FALSE;
217         }
218         
219         double wcx=0,wcy=0;
220         double cx=0,cy=0;
221
222         gint x,y;
223         Gdk::ModifierType state;
224
225         /* need to use the correct x,y, the event lies */
226         time_canvas_event_box.get_window()->get_pointer (x, y, state);
227
228         
229         track_canvas.c2w (x, y, wcx, wcy);
230         track_canvas.w2c (wcx, wcy, cx, cy);
231         
232         nframes_t where = leftmost_frame + pixel_to_frame (x);
233
234
235         /// ripped from maybe_autoscroll, and adapted to work here
236         nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
237         nframes_t rightmost_frame = leftmost_frame + one_page;
238
239         if (autoscroll_timeout_tag < 0) {
240                 if (where > rightmost_frame) {
241                         if (rightmost_frame < max_frames) {
242                                 start_canvas_autoscroll (1);
243                         }
244                 } else if (where <= leftmost_frame) {
245                         if (leftmost_frame > 0) {
246                                 start_canvas_autoscroll (-1);
247                         }
248                 } 
249         } else {
250                 if (where >= leftmost_frame && where < rightmost_frame) {
251                         stop_canvas_autoscroll ();
252                 }
253         }
254         //////  
255         
256         snap_to (where);
257
258         Cursor* cursor = 0;
259         
260         switch (ruler_pressed_button) {
261         case 1:
262                 /* transport playhead */
263                 cursor = playhead_cursor;
264                 break;
265
266         case 2:
267                 /* edit cursor */
268                 cursor = edit_cursor;
269                 break;
270
271         default:
272                 break;
273         }
274
275         if (cursor)
276         {
277                 cursor->set_position (where);
278                 
279                 if (cursor == edit_cursor) {
280                         edit_cursor_clock.set (where);
281                 }
282                 
283                 show_verbose_time_cursor (where, 10, cx, 0);
284         }
285         
286         return TRUE;
287 }
288
289
290 void
291 Editor::popup_ruler_menu (nframes_t where, ItemType t)
292 {
293         using namespace Menu_Helpers;
294
295         if (editor_ruler_menu == 0) {
296                 editor_ruler_menu = new Menu;
297                 editor_ruler_menu->set_name ("ArdourContextMenu");
298         }
299
300         // always build from scratch
301         MenuList& ruler_items = editor_ruler_menu->items();
302         editor_ruler_menu->set_name ("ArdourContextMenu");
303         ruler_items.clear();
304
305         CheckMenuItem * mitem;
306
307         no_ruler_shown_update = true;
308
309         switch (t) {
310         case MarkerBarItem:
311                 ruler_items.push_back (MenuElem (_("New location marker"), bind ( mem_fun(*this, &Editor::mouse_add_new_marker), where)));
312                 ruler_items.push_back (MenuElem (_("Clear all locations"), mem_fun(*this, &Editor::clear_markers)));
313                 ruler_items.push_back (SeparatorElem ());
314                 break;
315         case RangeMarkerBarItem:
316                 //ruler_items.push_back (MenuElem (_("New Range")));
317                 ruler_items.push_back (MenuElem (_("Clear all ranges"), mem_fun(*this, &Editor::clear_ranges)));
318                 ruler_items.push_back (SeparatorElem ());
319
320                 break;
321         case TransportMarkerBarItem:
322
323                 break;
324                 
325         case TempoBarItem:
326                 ruler_items.push_back (MenuElem (_("New Tempo"), bind ( mem_fun(*this, &Editor::mouse_add_new_tempo_event), where)));
327                 ruler_items.push_back (MenuElem (_("Clear tempo")));
328                 ruler_items.push_back (SeparatorElem ());
329                 break;
330
331         case MeterBarItem:
332                 ruler_items.push_back (MenuElem (_("New Meter"), bind ( mem_fun(*this, &Editor::mouse_add_new_meter_event), where)));
333                 ruler_items.push_back (MenuElem (_("Clear meter")));
334                 ruler_items.push_back (SeparatorElem ());
335                 break;
336
337         default:
338                 break;
339         }
340         
341         ruler_items.push_back (CheckMenuElem (_("Min:Secs"), bind (mem_fun(*this, &Editor::ruler_toggled), (int)ruler_metric_minsec)));
342         mitem = (CheckMenuItem *) &ruler_items.back(); 
343         if (ruler_shown[ruler_metric_minsec]) {
344                 mitem->set_active(true);
345         }
346
347         ruler_items.push_back (CheckMenuElem (X_("SMPTE"), bind (mem_fun(*this, &Editor::ruler_toggled), (int)ruler_metric_smpte)));
348         mitem = (CheckMenuItem *) &ruler_items.back(); 
349         if (ruler_shown[ruler_metric_smpte]) {
350                 mitem->set_active(true);
351         }
352
353         ruler_items.push_back (CheckMenuElem (_("Frames"), bind (mem_fun(*this, &Editor::ruler_toggled), (int)ruler_metric_frames)));
354         mitem = (CheckMenuItem *) &ruler_items.back(); 
355         if (ruler_shown[ruler_metric_frames]) {
356                 mitem->set_active(true);
357         }
358
359         ruler_items.push_back (CheckMenuElem (_("Bars:Beats"), bind (mem_fun(*this, &Editor::ruler_toggled), (int)ruler_metric_bbt)));
360         mitem = (CheckMenuItem *) &ruler_items.back(); 
361         if (ruler_shown[ruler_metric_bbt]) {
362                 mitem->set_active(true);
363         }
364
365         ruler_items.push_back (SeparatorElem ());
366
367         ruler_items.push_back (CheckMenuElem (_("Meter"), bind (mem_fun(*this, &Editor::ruler_toggled), (int)ruler_time_meter)));
368         mitem = (CheckMenuItem *) &ruler_items.back(); 
369         if (ruler_shown[ruler_time_meter]) {
370                 mitem->set_active(true);
371         }
372
373         ruler_items.push_back (CheckMenuElem (_("Tempo"), bind (mem_fun(*this, &Editor::ruler_toggled), (int)ruler_time_tempo)));
374         mitem = (CheckMenuItem *) &ruler_items.back(); 
375         if (ruler_shown[ruler_time_tempo]) {
376                 mitem->set_active(true);
377         }
378
379         ruler_items.push_back (CheckMenuElem (_("Location Markers"), bind (mem_fun(*this, &Editor::ruler_toggled), (int)ruler_time_marker)));
380         mitem = (CheckMenuItem *) &ruler_items.back(); 
381         if (ruler_shown[ruler_time_marker]) {
382                 mitem->set_active(true);
383         }
384
385         ruler_items.push_back (CheckMenuElem (_("Range Markers"), bind (mem_fun(*this, &Editor::ruler_toggled), (int)ruler_time_range_marker)));
386         mitem = (CheckMenuItem *) &ruler_items.back(); 
387         if (ruler_shown[ruler_time_range_marker]) {
388                 mitem->set_active(true);
389         }
390
391         ruler_items.push_back (CheckMenuElem (_("Loop/Punch Ranges"), bind (mem_fun(*this, &Editor::ruler_toggled), (int)ruler_time_transport_marker)));
392         mitem = (CheckMenuItem *) &ruler_items.back(); 
393         if (ruler_shown[ruler_time_transport_marker]) {
394                 mitem->set_active(true);
395         }
396         
397         editor_ruler_menu->popup (1, 0);
398
399         no_ruler_shown_update = false;
400 }
401
402 void
403 Editor::ruler_toggled (int ruler)
404 {
405         if (!session) return;
406         if (ruler < 0 || ruler >= (int) sizeof(ruler_shown)) return;
407
408         if (no_ruler_shown_update) return;
409
410         if (ruler_shown[ruler]) {
411                 if (visible_timebars <= 1) {
412                         // must always have 1 visible
413                         return;
414                 }
415         }
416         
417         ruler_shown[ruler] = !ruler_shown[ruler];
418
419         update_ruler_visibility ();
420
421         // update session extra RulerVisibility
422         store_ruler_visibility ();
423 }
424
425 void
426 Editor::store_ruler_visibility ()
427 {
428         XMLNode* node = new XMLNode(X_("RulerVisibility"));
429
430         node->add_property (X_("smpte"), ruler_shown[ruler_metric_smpte] ? "yes": "no");
431         node->add_property (X_("bbt"), ruler_shown[ruler_metric_bbt] ? "yes": "no");
432         node->add_property (X_("frames"), ruler_shown[ruler_metric_frames] ? "yes": "no");
433         node->add_property (X_("minsec"), ruler_shown[ruler_metric_minsec] ? "yes": "no");
434         node->add_property (X_("tempo"), ruler_shown[ruler_time_tempo] ? "yes": "no");
435         node->add_property (X_("meter"), ruler_shown[ruler_time_meter] ? "yes": "no");
436         node->add_property (X_("marker"), ruler_shown[ruler_time_marker] ? "yes": "no");
437         node->add_property (X_("rangemarker"), ruler_shown[ruler_time_range_marker] ? "yes": "no");
438         node->add_property (X_("transportmarker"), ruler_shown[ruler_time_transport_marker] ? "yes": "no");
439
440         session->add_extra_xml (*node);
441         session->set_dirty ();
442 }
443  
444 void 
445 Editor::restore_ruler_visibility ()
446 {
447         XMLProperty* prop;
448         XMLNode * node = session->extra_xml (X_("RulerVisibility"));
449
450         if (node) {
451                 if ((prop = node->property ("smpte")) != 0) {
452                         if (prop->value() == "yes") 
453                                 ruler_shown[ruler_metric_smpte] = true;
454                         else 
455                                 ruler_shown[ruler_metric_smpte] = false;
456                 }
457                 if ((prop = node->property ("bbt")) != 0) {
458                         if (prop->value() == "yes") 
459                                 ruler_shown[ruler_metric_bbt] = true;
460                         else 
461                                 ruler_shown[ruler_metric_bbt] = false;
462                 }
463                 if ((prop = node->property ("frames")) != 0) {
464                         if (prop->value() == "yes") 
465                                 ruler_shown[ruler_metric_frames] = true;
466                         else 
467                                 ruler_shown[ruler_metric_frames] = false;
468                 }
469                 if ((prop = node->property ("minsec")) != 0) {
470                         if (prop->value() == "yes") 
471                                 ruler_shown[ruler_metric_minsec] = true;
472                         else 
473                                 ruler_shown[ruler_metric_minsec] = false;
474                 }
475                 if ((prop = node->property ("tempo")) != 0) {
476                         if (prop->value() == "yes") 
477                                 ruler_shown[ruler_time_tempo] = true;
478                         else 
479                                 ruler_shown[ruler_time_tempo] = false;
480                 }
481                 if ((prop = node->property ("meter")) != 0) {
482                         if (prop->value() == "yes") 
483                                 ruler_shown[ruler_time_meter] = true;
484                         else 
485                                 ruler_shown[ruler_time_meter] = false;
486                 }
487                 if ((prop = node->property ("marker")) != 0) {
488                         if (prop->value() == "yes") 
489                                 ruler_shown[ruler_time_marker] = true;
490                         else 
491                                 ruler_shown[ruler_time_marker] = false;
492                 }
493                 if ((prop = node->property ("rangemarker")) != 0) {
494                         if (prop->value() == "yes") 
495                                 ruler_shown[ruler_time_range_marker] = true;
496                         else 
497                                 ruler_shown[ruler_time_range_marker] = false;
498                 }
499                 if ((prop = node->property ("transportmarker")) != 0) {
500                         if (prop->value() == "yes") 
501                                 ruler_shown[ruler_time_transport_marker] = true;
502                         else 
503                                 ruler_shown[ruler_time_transport_marker] = false;
504                 }
505
506         }
507
508         update_ruler_visibility ();
509 }
510
511
512 void
513 Editor::update_ruler_visibility ()
514 {
515         using namespace Box_Helpers;
516         BoxList & lab_children =  time_button_vbox.children();
517         BoxList & ruler_children =  time_canvas_vbox.children();
518
519         visible_timebars = 0;
520
521         lab_children.clear();
522
523         // leave the last one (the time_canvas) intact
524         while (ruler_children.size() > 1) {
525                 ruler_children.pop_front();
526         }
527
528         BoxList::iterator canvaspos = ruler_children.begin();
529         
530         _smpte_ruler = gtk_custom_hruler_new ();
531         smpte_ruler = Glib::wrap (_smpte_ruler);
532         smpte_ruler->set_name ("SMPTERuler");
533         smpte_ruler->set_size_request (-1, (int)timebar_height);
534         gtk_custom_ruler_set_metric (GTK_CUSTOM_RULER(_smpte_ruler), &ruler_metrics[ruler_metric_smpte]);
535         
536         _bbt_ruler = gtk_custom_hruler_new ();
537         bbt_ruler = Glib::wrap (_bbt_ruler);
538         bbt_ruler->set_name ("BBTRuler");
539         bbt_ruler->set_size_request (-1, (int)timebar_height);
540         gtk_custom_ruler_set_metric (GTK_CUSTOM_RULER(_bbt_ruler), &ruler_metrics[ruler_metric_bbt]);
541
542         _frames_ruler = gtk_custom_hruler_new ();
543         frames_ruler = Glib::wrap (_frames_ruler);
544         frames_ruler->set_name ("FramesRuler");
545         frames_ruler->set_size_request (-1, (int)timebar_height);
546         gtk_custom_ruler_set_metric (GTK_CUSTOM_RULER(_frames_ruler), &ruler_metrics[ruler_metric_frames]);
547
548         _minsec_ruler = gtk_custom_hruler_new ();
549         minsec_ruler = Glib::wrap (_minsec_ruler);
550         minsec_ruler->set_name ("MinSecRuler");
551         minsec_ruler->set_size_request (-1, (int)timebar_height);
552         gtk_custom_ruler_set_metric (GTK_CUSTOM_RULER(_minsec_ruler), &ruler_metrics[ruler_metric_minsec]);
553
554         
555         smpte_ruler->set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
556         bbt_ruler->set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
557         frames_ruler->set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
558         minsec_ruler->set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
559
560         smpte_ruler->signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_button_release));
561         bbt_ruler->signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_button_release));
562         frames_ruler->signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_button_release));
563         minsec_ruler->signal_button_release_event().connect (mem_fun(*this, &Editor::ruler_button_release));
564
565         smpte_ruler->signal_button_press_event().connect (mem_fun(*this, &Editor::ruler_button_press));
566         bbt_ruler->signal_button_press_event().connect (mem_fun(*this, &Editor::ruler_button_press));
567         frames_ruler->signal_button_press_event().connect (mem_fun(*this, &Editor::ruler_button_press));
568         minsec_ruler->signal_button_press_event().connect (mem_fun(*this, &Editor::ruler_button_press));
569         
570         smpte_ruler->signal_motion_notify_event().connect (mem_fun(*this, &Editor::ruler_mouse_motion));
571         bbt_ruler->signal_motion_notify_event().connect (mem_fun(*this, &Editor::ruler_mouse_motion));
572         frames_ruler->signal_motion_notify_event().connect (mem_fun(*this, &Editor::ruler_mouse_motion));
573         minsec_ruler->signal_motion_notify_event().connect (mem_fun(*this, &Editor::ruler_mouse_motion));
574
575         
576         if (ruler_shown[ruler_metric_minsec]) {
577                 lab_children.push_back (Element(minsec_label, PACK_SHRINK, PACK_START));
578                 ruler_children.insert (canvaspos, Element(*minsec_ruler, PACK_SHRINK, PACK_START));
579                 visible_timebars++;
580         }
581
582         if (ruler_shown[ruler_metric_smpte]) {
583                 lab_children.push_back (Element(smpte_label, PACK_SHRINK, PACK_START));
584                 ruler_children.insert (canvaspos, Element(*smpte_ruler, PACK_SHRINK, PACK_START));
585                 visible_timebars++;
586         }
587
588         if (ruler_shown[ruler_metric_frames]) {
589                 lab_children.push_back (Element(frame_label, PACK_SHRINK, PACK_START));
590                 ruler_children.insert (canvaspos, Element(*frames_ruler, PACK_SHRINK, PACK_START));
591                 visible_timebars++;
592         }
593
594         if (ruler_shown[ruler_metric_bbt]) {
595                 lab_children.push_back (Element(bbt_label, PACK_SHRINK, PACK_START));
596                 ruler_children.insert (canvaspos, Element(*bbt_ruler, PACK_SHRINK, PACK_START));
597                 visible_timebars++;
598         }
599
600         double tbpos = 0.0;
601         double old_unit_pos ;
602         
603         if (ruler_shown[ruler_time_meter]) {
604                 lab_children.push_back (Element(meter_label, PACK_SHRINK, PACK_START));
605
606                 old_unit_pos = meter_group->property_y();
607                 if (tbpos != old_unit_pos) {
608                         meter_group->move ( 0.0, tbpos - old_unit_pos);
609                 }
610                 meter_group->show();
611                 tbpos += timebar_height;
612                 visible_timebars++;
613         }
614         else {
615                 meter_group->hide();
616         }
617         
618         if (ruler_shown[ruler_time_tempo]) {
619                 lab_children.push_back (Element(tempo_label, PACK_SHRINK, PACK_START));
620                 old_unit_pos = tempo_group->property_y();
621                 if (tbpos != old_unit_pos) {
622                         tempo_group->move(0.0, tbpos - old_unit_pos);
623                 }
624                 tempo_group->show();
625                 tbpos += timebar_height;
626                 visible_timebars++;
627         }
628         else {
629                 tempo_group->hide();
630         }
631         
632         if (ruler_shown[ruler_time_marker]) {
633                 lab_children.push_back (Element(mark_label, PACK_SHRINK, PACK_START));
634                 old_unit_pos = marker_group->property_y();
635                 if (tbpos != old_unit_pos) {
636                         marker_group->move ( 0.0, tbpos - old_unit_pos);
637                 }
638                 marker_group->show();
639                 tbpos += timebar_height;
640                 visible_timebars++;
641         }
642         else {
643                 marker_group->hide();
644         }
645         
646         if (ruler_shown[ruler_time_range_marker]) {
647                 lab_children.push_back (Element(range_mark_label, PACK_SHRINK, PACK_START));
648                 old_unit_pos = range_marker_group->property_y();
649                 if (tbpos != old_unit_pos) {
650                         range_marker_group->move (0.0, tbpos - old_unit_pos);
651                 }
652                 range_marker_group->show();
653                 tbpos += timebar_height;
654                 visible_timebars++;
655         }
656         else {
657                 range_marker_group->hide();
658         }
659
660         if (ruler_shown[ruler_time_transport_marker]) {
661                 lab_children.push_back (Element(transport_mark_label, PACK_SHRINK, PACK_START));
662                 old_unit_pos = transport_marker_group->property_y();
663                 if (tbpos != old_unit_pos) {
664                         transport_marker_group->move ( 0.0, tbpos - old_unit_pos);
665                 }
666                 transport_marker_group->show();
667                 tbpos += timebar_height;
668                 visible_timebars++;
669         }
670         else {
671                 transport_marker_group->hide();
672         }
673         
674         time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars));
675         time_canvas_event_box.queue_resize();
676         
677         update_fixed_rulers();
678         //update_tempo_based_rulers();
679         tempo_map_changed(Change (0));
680
681         time_canvas_event_box.show_all();
682         time_button_event_box.show_all();
683 }
684
685 void
686 Editor::update_just_smpte ()
687 {
688         ENSURE_GUI_THREAD(mem_fun(*this, &Editor::update_just_smpte));
689         
690         if (session == 0) {
691                 return;
692         }
693
694         /* XXX Note the potential loss of accuracy here as we convert from
695            an uint32_t (or larger) to a float ... what to do ?
696         */
697
698         nframes_t page = (nframes_t) floor (canvas_width * frames_per_unit);
699         nframes_t rightmost_frame = leftmost_frame + page;
700
701         if (ruler_shown[ruler_metric_smpte]) {
702                 gtk_custom_ruler_set_range (GTK_CUSTOM_RULER(_smpte_ruler), leftmost_frame, rightmost_frame,
703                                             leftmost_frame, session->current_end_frame());
704         }
705 }
706
707 void
708 Editor::update_fixed_rulers ()
709 {
710         nframes_t rightmost_frame;
711
712         if (session == 0) {
713                 return;
714         }
715
716         /* XXX Note the potential loss of accuracy here as we convert from
717            an uint32_t (or larger) to a float ... what to do ?
718         */
719
720         nframes_t page = (nframes_t) floor (canvas_width * frames_per_unit);
721
722         ruler_metrics[ruler_metric_smpte].units_per_pixel = frames_per_unit;
723         ruler_metrics[ruler_metric_frames].units_per_pixel = frames_per_unit;
724         ruler_metrics[ruler_metric_minsec].units_per_pixel = frames_per_unit;
725
726         rightmost_frame = leftmost_frame + page;
727
728         /* these force a redraw, which in turn will force execution of the metric callbacks
729            to compute the relevant ticks to display.
730         */
731
732         if (ruler_shown[ruler_metric_smpte]) {
733                 gtk_custom_ruler_set_range (GTK_CUSTOM_RULER(_smpte_ruler), leftmost_frame, rightmost_frame,
734                                             leftmost_frame, session->current_end_frame());
735         }
736         
737         if (ruler_shown[ruler_metric_frames]) {
738                 gtk_custom_ruler_set_range (GTK_CUSTOM_RULER(_frames_ruler), leftmost_frame, rightmost_frame,
739                                             leftmost_frame, session->current_end_frame());
740         }
741         
742         if (ruler_shown[ruler_metric_minsec]) {
743                 gtk_custom_ruler_set_range (GTK_CUSTOM_RULER(_minsec_ruler), leftmost_frame, rightmost_frame,
744                                             leftmost_frame, session->current_end_frame());
745         }
746 }               
747
748 void
749 Editor::update_tempo_based_rulers ()
750 {
751         if (session == 0) {
752                 return;
753         }
754
755         /* XXX Note the potential loss of accuracy here as we convert from
756            an uint32_t (or larger) to a float ... what to do ?
757         */
758
759         nframes_t page = (nframes_t) floor (canvas_width * frames_per_unit);
760         ruler_metrics[ruler_metric_bbt].units_per_pixel = frames_per_unit;
761
762         if (ruler_shown[ruler_metric_bbt]) {
763                 gtk_custom_ruler_set_range (GTK_CUSTOM_RULER(_bbt_ruler), leftmost_frame, leftmost_frame+page, 
764                                             leftmost_frame, session->current_end_frame());
765         }
766 }
767
768 /* Mark generation */
769
770 gint
771 Editor::_metric_get_smpte (GtkCustomRulerMark **marks, gdouble lower, gdouble upper, gint maxchars)
772 {
773         return ruler_editor->metric_get_smpte (marks, lower, upper, maxchars);
774 }
775
776 gint
777 Editor::_metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble upper, gint maxchars)
778 {
779         return ruler_editor->metric_get_bbt (marks, lower, upper, maxchars);
780 }
781
782 gint
783 Editor::_metric_get_frames (GtkCustomRulerMark **marks, gdouble lower, gdouble upper, gint maxchars)
784 {
785         return ruler_editor->metric_get_frames (marks, lower, upper, maxchars);
786 }
787
788 gint
789 Editor::_metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble upper, gint maxchars)
790 {
791         return ruler_editor->metric_get_minsec (marks, lower, upper, maxchars);
792 }
793
794 gint
795 Editor::metric_get_smpte (GtkCustomRulerMark **marks, gdouble lower, gdouble upper, gint maxchars)
796 {
797         nframes_t range;
798         nframes_t pos;
799         nframes_t spacer;
800         nframes_t fr;
801         SMPTE::Time smpte;
802         gchar buf[16];
803         gint nmarks = 0;
804         gint n;
805         bool show_bits = false;
806         bool show_frames = false;
807         bool show_seconds = false;
808         bool show_minutes = false;
809         bool show_hours = false;
810         int mark_modulo;
811
812         if (session == 0) {
813                 return 0;
814         }
815
816         fr = session->frame_rate();
817
818         if (lower > (spacer = (nframes_t)(128 * Editor::get_current_zoom ()))) {
819                 lower = lower - spacer;
820         } else {
821                 lower = 0;
822         }
823         upper = upper + spacer;
824         range = (nframes_t) floor (upper - lower);
825
826         if (range < (2 * session->frames_per_smpte_frame())) { /* 0 - 2 frames */
827                 show_bits = true;
828                 mark_modulo = 20;
829                 nmarks = 1 + 160;
830         } else if (range <= (fr / 4)) { /* 2 frames - 0.250 second */
831                 show_frames = true;
832                 mark_modulo = 1;
833                 nmarks = 1 + (range / (nframes_t)session->frames_per_smpte_frame());
834         } else if (range <= (fr / 2)) { /* 0.25-0.5 second */
835                 show_frames = true;
836                 mark_modulo = 2;
837                 nmarks = 1 + (range / (nframes_t)session->frames_per_smpte_frame());
838         } else if (range <= fr) { /* 0.5-1 second */
839                 show_frames = true;
840                 mark_modulo = 5;
841                 nmarks = 1 + (range / (nframes_t)session->frames_per_smpte_frame());
842         } else if (range <= 2 * fr) { /* 1-2 seconds */
843                 show_frames = true;
844                 mark_modulo = 10;
845                 nmarks = 1 + (range / (nframes_t)session->frames_per_smpte_frame());
846         } else if (range <= 8 * fr) { /* 2-8 seconds */
847                 show_seconds = true;
848                 mark_modulo = 1;
849                 nmarks = 1 + (range / fr);
850         } else if (range <= 16 * fr) { /* 8-16 seconds */
851                 show_seconds = true;
852                 mark_modulo = 2;
853                 nmarks = 1 + (range / fr);
854         } else if (range <= 30 * fr) { /* 16-30 seconds */
855                 show_seconds = true;
856                 mark_modulo = 5;
857                 nmarks = 1 + (range / fr);
858         } else if (range <= 60 * fr) { /* 30-60 seconds */
859                 show_seconds = true;
860                 mark_modulo = 5;
861                 nmarks = 1 + (range / fr);
862         } else if (range <= 2 * 60 * fr) { /* 1-2 minutes */
863                 show_seconds = true;
864                 mark_modulo = 20;
865                 nmarks = 1 + (range / fr);
866         } else if (range <= 4 * 60 * fr) { /* 2-4 minutes */
867                 show_seconds = true;
868                 mark_modulo = 30;
869                 nmarks = 1 + (range / fr);
870         } else if (range <= 10 * 60 * fr) { /* 4-10 minutes */
871                 show_minutes = true;
872                 mark_modulo = 2;
873                 nmarks = 1 + 10;
874         } else if (range <= 30 * 60 * fr) { /* 10-30 minutes */
875                 show_minutes = true;
876                 mark_modulo = 5;
877                 nmarks = 1 + 30;
878         } else if (range <= 60 * 60 * fr) { /* 30 minutes - 1hr */
879                 show_minutes = true;
880                 mark_modulo = 10;
881                 nmarks = 1 + 60;
882         } else if (range <= 4 * 60 * 60 * fr) { /* 1 - 4 hrs*/
883                 show_minutes = true;
884                 mark_modulo = 30;
885                 nmarks = 1 + (60 * 4);
886         } else if (range <= 8 * 60 * 60 * fr) { /* 4 - 8 hrs*/
887                 show_hours = true;
888                 mark_modulo = 1;
889                 nmarks = 1 + 8;
890         } else if (range <= 16 * 60 * 60 * fr) { /* 16-24 hrs*/
891                 show_hours = true;
892                 mark_modulo = 1;
893                 nmarks = 1 + 24;
894         } else {
895     
896                 /* not possible if nframes_t is a 32 bit quantity */
897     
898                 show_hours = true;
899                 mark_modulo = 4;
900                 nmarks = 1 + 24;
901         }
902   
903         pos = (nframes_t) floor (lower);
904         
905         *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks);  
906         
907         if (show_bits) {
908                 // Find smpte time of this sample (pos) with subframe accuracy
909                 session->sample_to_smpte(pos, smpte, true /* use_offset */, true /* use_subframes */ );
910     
911                 for (n = 0; n < nmarks; n++) {
912                         session->smpte_to_sample(smpte, pos, true /* use_offset */, true /* use_subframes */ );
913                         if ((smpte.subframes % mark_modulo) == 0) {
914                                 if (smpte.subframes == 0) {
915                                         (*marks)[n].style = GtkCustomRulerMarkMajor;
916                                         snprintf (buf, sizeof(buf), "%s%02u:%02u:%02u:%02u", smpte.negative ? "-" : "", smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
917                                 } else {
918                                         (*marks)[n].style = GtkCustomRulerMarkMinor;
919                                         snprintf (buf, sizeof(buf), ".%02u", smpte.subframes);
920                                 }
921                         } else {
922                                 snprintf (buf, sizeof(buf)," ");
923                                 (*marks)[n].style = GtkCustomRulerMarkMicro;
924         
925                         }
926                         (*marks)[n].label = g_strdup (buf);
927                         (*marks)[n].position = pos;
928
929                         // Increment subframes by one
930                         SMPTE::increment_subframes( smpte );
931                 }
932         } else if (show_seconds) {
933                 // Find smpte time of this sample (pos)
934                 session->sample_to_smpte(pos, smpte, true /* use_offset */, false /* use_subframes */ );
935                 // Go to next whole second down
936                 SMPTE::seconds_floor( smpte );
937
938                 for (n = 0; n < nmarks; n++) {
939                         session->smpte_to_sample(smpte, pos, true /* use_offset */, false /* use_subframes */ );
940                         if ((smpte.seconds % mark_modulo) == 0) {
941                                 if (smpte.seconds == 0) {
942                                         (*marks)[n].style = GtkCustomRulerMarkMajor;
943                                         (*marks)[n].position = pos;
944                                 } else {
945                                         (*marks)[n].style = GtkCustomRulerMarkMinor;
946                                         (*marks)[n].position = pos;
947                                 }
948                                 snprintf (buf, sizeof(buf), "%s%02u:%02u:%02u:%02u", smpte.negative ? "-" : "", smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
949                         } else {
950                                 snprintf (buf, sizeof(buf)," ");
951                                 (*marks)[n].style = GtkCustomRulerMarkMicro;
952                                 (*marks)[n].position = pos;
953         
954                         }
955                         (*marks)[n].label = g_strdup (buf);
956                         SMPTE::increment_seconds( smpte );
957                 }
958         } else if (show_minutes) {
959                 // Find smpte time of this sample (pos)
960                 session->sample_to_smpte(pos, smpte, true /* use_offset */, false /* use_subframes */ );
961                 // Go to next whole minute down
962                 SMPTE::minutes_floor( smpte );
963
964                 for (n = 0; n < nmarks; n++) {
965                         session->smpte_to_sample(smpte, pos, true /* use_offset */, false /* use_subframes */ );
966                         if ((smpte.minutes % mark_modulo) == 0) {
967                                 if (smpte.minutes == 0) {
968                                         (*marks)[n].style = GtkCustomRulerMarkMajor;
969                                 } else {
970                                         (*marks)[n].style = GtkCustomRulerMarkMinor;
971                                 }
972                                 snprintf (buf, sizeof(buf), "%s%02u:%02u:%02u:%02u", smpte.negative ? "-" : "", smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
973                         } else {
974                                 snprintf (buf, sizeof(buf)," ");
975                                 (*marks)[n].style = GtkCustomRulerMarkMicro;
976         
977                         }
978                         (*marks)[n].label = g_strdup (buf);
979                         (*marks)[n].position = pos;
980                         SMPTE::increment_minutes( smpte );
981                 }
982         } else if (show_hours) {
983                 // Find smpte time of this sample (pos)
984                 session->sample_to_smpte(pos, smpte, true /* use_offset */, false /* use_subframes */ );
985                 // Go to next whole hour down
986                 SMPTE::hours_floor( smpte );
987
988                 for (n = 0; n < nmarks; n++) {
989                         session->smpte_to_sample(smpte, pos, true /* use_offset */, false /* use_subframes */ );
990                         if ((smpte.hours % mark_modulo) == 0) {
991                                 (*marks)[n].style = GtkCustomRulerMarkMajor;
992                                 snprintf (buf, sizeof(buf), "%s%02u:%02u:%02u:%02u", smpte.negative ? "-" : "", smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
993                         } else {
994                                 snprintf (buf, sizeof(buf)," ");
995                                 (*marks)[n].style = GtkCustomRulerMarkMicro;
996         
997                         }
998                         (*marks)[n].label = g_strdup (buf);
999                         (*marks)[n].position = pos;
1000
1001                         SMPTE::increment_hours( smpte );
1002                 }
1003         } else { // show_frames
1004                 // Find smpte time of this sample (pos)
1005                 session->sample_to_smpte(pos, smpte, true /* use_offset */, false /* use_subframes */ );
1006                 // Go to next whole frame down
1007                 SMPTE::frames_floor( smpte );
1008
1009                 for (n = 0; n < nmarks; n++) {
1010                         session->smpte_to_sample(smpte, pos, true /* use_offset */, false /* use_subframes */ );
1011                         if ((smpte.frames % mark_modulo) == 0)  {
1012                                 (*marks)[n].style = GtkCustomRulerMarkMajor;
1013                                 (*marks)[n].position = pos;
1014                                 snprintf (buf, sizeof(buf), "%s%02u:%02u:%02u:%02u", smpte.negative ? "-" : "", smpte.hours, smpte.minutes, smpte.seconds, smpte.frames);
1015                         } else {
1016                                 snprintf (buf, sizeof(buf)," ");
1017                                 (*marks)[n].style = GtkCustomRulerMarkMicro;
1018                                 (*marks)[n].position = pos;
1019         
1020                         }
1021                         (*marks)[n].label = g_strdup (buf);
1022                         SMPTE::increment( smpte );
1023                 }
1024         }
1025   
1026         return nmarks;
1027 }
1028
1029
1030 gint
1031 Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble upper, gint maxchars)
1032 {
1033         if (session == 0) {
1034                 return 0;
1035         }
1036
1037         TempoMap::BBTPointList::iterator i;
1038
1039         uint32_t beats = 0;
1040         uint32_t bars = 0;
1041         uint32_t desirable_marks;
1042         uint32_t magic_accent_number = 1;
1043         gint nmarks;
1044         char buf[64];
1045         gint  n = 0;
1046         nframes_t pos;
1047         bool bar_helper_on = true;
1048        
1049         BBT_Time next_beat;
1050         nframes_t next_beat_pos;
1051
1052         if ((desirable_marks = maxchars / 7) == 0) {
1053                return 0;
1054         }
1055
1056         /* align the tick marks to whatever we're snapping to... */
1057
1058         switch (snap_type) {
1059         case SnapToAThirdBeat:
1060                 bbt_beat_subdivision = 3;
1061                 break;
1062         case SnapToAQuarterBeat:
1063                 bbt_beat_subdivision = 4;
1064                 break;
1065         case SnapToAEighthBeat:
1066                 bbt_beat_subdivision = 8;
1067                 magic_accent_number = 2;
1068                 break;
1069         case SnapToASixteenthBeat:
1070                 bbt_beat_subdivision = 16;
1071                 magic_accent_number = 4;
1072                 break;
1073         case SnapToAThirtysecondBeat:
1074                 bbt_beat_subdivision = 32;
1075                 magic_accent_number = 8;
1076                 break;
1077         default:
1078                bbt_beat_subdivision = 4;
1079                 break;
1080         }
1081
1082         if (current_bbt_points == 0 || current_bbt_points->empty()) {
1083                 return 0;
1084         }
1085
1086         i = current_bbt_points->end();
1087         i--;
1088         bars = (*i).bar - (*current_bbt_points->begin()).bar;
1089         beats = current_bbt_points->size() - bars;
1090
1091         /*Only show the bar helper if there aren't many bars on the screen */
1092         if (bars > 1) {
1093                 bar_helper_on = false;
1094         }
1095
1096         if (desirable_marks > (beats / 4)) {
1097
1098                 /* we're in beat land...*/
1099
1100                 uint32_t tick = 0;
1101                 uint32_t skip;
1102                 uint32_t t;
1103                 nframes_t frame_skip;
1104                 double frame_skip_error;
1105                 double accumulated_error;
1106                 double position_of_helper;
1107                 bool i_am_accented = false;
1108                 bool we_need_ticks = false;
1109                 bool helper_active = false;
1110         
1111                 position_of_helper = lower + (30 * Editor::get_current_zoom ());
1112
1113                 if (desirable_marks >= (beats)) {
1114                         nmarks = (beats * bbt_beat_subdivision) + 1;
1115                         we_need_ticks = true;
1116                 } else {
1117                         nmarks = beats + 1;
1118                 }
1119
1120                 *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks);
1121
1122                 (*marks)[0].label = g_strdup(" ");
1123                 (*marks)[0].position = lower;
1124                 (*marks)[0].style = GtkCustomRulerMarkMicro;
1125                 
1126                 for (n = 1,   i = current_bbt_points->begin(); n < nmarks && i != current_bbt_points->end(); ++i) {
1127
1128                         if ((*i).frame < lower && (bar_helper_on)) {
1129                                         snprintf (buf, sizeof(buf), "<%" PRIu32 "|%" PRIu32, (*i).bar, (*i).beat);
1130                                         (*marks)[0].label = g_strdup (buf); 
1131                                         helper_active = true;
1132                         } else {
1133
1134                           if ((*i).type == TempoMap::Bar)  {
1135                             if (((*i).frame < position_of_helper) && helper_active) {
1136                               snprintf (buf, sizeof(buf), " ");
1137                             } else {
1138                               snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar);
1139                             }
1140                             (*marks)[n].label = g_strdup (buf);
1141                             (*marks)[n].position = (*i).frame;
1142                             (*marks)[n].style = GtkCustomRulerMarkMajor;
1143                             n++;
1144                             
1145                           } else if (((*i).type == TempoMap::Beat) && ((*i).beat > 1)) {
1146                             ((((*i).frame < position_of_helper) && bar_helper_on) || !we_need_ticks) ?
1147                               snprintf (buf, sizeof(buf), " ") : snprintf (buf, sizeof(buf), "%" PRIu32, (*i).beat);
1148                             if (((*i).beat % 2 == 1) || we_need_ticks) {
1149                               (*marks)[n].style = GtkCustomRulerMarkMinor;
1150                             } else {
1151                               (*marks)[n].style = GtkCustomRulerMarkMicro;
1152                             }
1153                             (*marks)[n].label =  g_strdup (buf);
1154                             (*marks)[n].position = (*i).frame;
1155                             n++;
1156                           }
1157
1158                         }
1159
1160
1161                         /* Add the tick marks */
1162
1163                         if (we_need_ticks && (*i).type == TempoMap::Beat) {
1164
1165                                 /* Find the next beat */
1166
1167                                 next_beat.beats = (*i).beat;
1168                                 next_beat.bars = (*i).bar;
1169
1170                                 if ((*i).meter->beats_per_bar() > (next_beat.beats + 1)) {
1171                                   next_beat.beats += 1;
1172                                 } else {
1173                                   next_beat.bars += 1;
1174                                   next_beat.beats = 1;
1175                                 }
1176                                 
1177                                 next_beat_pos = session->tempo_map().frame_time(next_beat);
1178
1179                                 frame_skip = (nframes_t) floor (frame_skip_error = (session->frame_rate() *  60) / (bbt_beat_subdivision * (*i).tempo->beats_per_minute()));
1180                                 frame_skip_error -= frame_skip;
1181                                 skip = (uint32_t) (Meter::ticks_per_beat / bbt_beat_subdivision);
1182
1183                                 pos = (*i).frame + frame_skip;
1184                                 accumulated_error = frame_skip_error;
1185
1186                                 tick = skip;
1187
1188                                 for (t = 0; (tick < Meter::ticks_per_beat) && (n < nmarks) && (pos < next_beat_pos) ; pos += frame_skip, tick += skip, ++t) {
1189
1190                                         if (t % magic_accent_number == (magic_accent_number - 1)) {
1191                                                 i_am_accented = true;
1192                                         }
1193                                         if (Editor::get_current_zoom () > 32) {
1194                                                 snprintf (buf, sizeof(buf), " ");
1195                                         } else if ((Editor::get_current_zoom () > 8) && !i_am_accented) {
1196                                                 snprintf (buf, sizeof(buf), " ");
1197                                         } else  if (bar_helper_on && (pos < position_of_helper)) {
1198                                                 snprintf (buf, sizeof(buf), " ");
1199                                         } else {
1200                                                 snprintf (buf, sizeof(buf), "%" PRIu32, tick);
1201                                         }
1202
1203                                         (*marks)[n].label = g_strdup (buf);
1204
1205                                         /* Error compensation for float to nframes_t*/
1206                                         accumulated_error += frame_skip_error;
1207                                         if (accumulated_error > 1) {
1208                                                 pos += 1;
1209                                                 accumulated_error -= 1.0f;
1210                                         }
1211
1212                                         (*marks)[n].position = pos;
1213
1214                                         if ((bbt_beat_subdivision > 4) && i_am_accented) {
1215                                                 (*marks)[n].style = GtkCustomRulerMarkMinor;
1216                                         } else {
1217                                                 (*marks)[n].style = GtkCustomRulerMarkMicro;
1218                                         }
1219                                         i_am_accented = false;
1220                                         n++;
1221                                 
1222                                 }
1223                         }
1224                 }
1225                 return n; //return the actual number of marks made, since we might have skipped some fro fractional time signatures 
1226
1227        } else {
1228
1229                 /* we're in bar land */
1230
1231                 if (desirable_marks < (bars / 256)) {
1232                         nmarks = 1;
1233                         *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks);
1234                         snprintf (buf, sizeof(buf), "too many bars... (currently %" PRIu32 ")", bars );
1235                         (*marks)[0].style = GtkCustomRulerMarkMajor;
1236                         (*marks)[0].label = g_strdup (buf);
1237                         (*marks)[0].position = lower;
1238                 } else if (desirable_marks < (uint32_t)(nmarks = (gint) (bars / 64) + 1)) {
1239                         *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks);
1240                         for (n = 0,   i = current_bbt_points->begin(); i != current_bbt_points->end() && n < nmarks; i++) {
1241                                 if ((*i).type == TempoMap::Bar)  {
1242                                         if ((*i).bar % 64 == 1) {
1243                                                 if ((*i).bar % 256 == 1) {
1244                                                         snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar);
1245                                                         (*marks)[n].style = GtkCustomRulerMarkMajor;
1246                                                 } else {
1247                                                         snprintf (buf, sizeof(buf), " ");
1248                                                         if ((*i).bar % 256 == 129)  {
1249                                                                 (*marks)[n].style = GtkCustomRulerMarkMinor;
1250                                                         } else {
1251                                                                 (*marks)[n].style = GtkCustomRulerMarkMicro;
1252                                                         }
1253                                                 }
1254                                                 (*marks)[n].label = g_strdup (buf);
1255                                                 (*marks)[n].position = (*i).frame;
1256                                                 n++;
1257                                         }
1258                                 }
1259                         }
1260                 } else if (desirable_marks < (uint32_t)(nmarks = (bars / 16) + 1)) {
1261                         *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks);
1262                         for (n = 0,  i = current_bbt_points->begin(); i != current_bbt_points->end() && n < nmarks; i++) {
1263                                 if ((*i).type == TempoMap::Bar)  {
1264                                         if ((*i).bar % 16 == 1) {
1265                                                 if ((*i).bar % 64 == 1) {
1266                                                         snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar);
1267                                                         (*marks)[n].style = GtkCustomRulerMarkMajor;
1268                                                 } else {
1269                                                         snprintf (buf, sizeof(buf), " ");
1270                                                         if ((*i).bar % 64 == 33)  {
1271                                                                 (*marks)[n].style = GtkCustomRulerMarkMinor;
1272                                                         } else {
1273                                                                 (*marks)[n].style = GtkCustomRulerMarkMicro;
1274                                                         }
1275                                                 }
1276                                                 (*marks)[n].label = g_strdup (buf);
1277                                                 (*marks)[n].position = (*i).frame;
1278                                                 n++;
1279                                         }
1280                                 }
1281                         }
1282                 } else if (desirable_marks < (uint32_t)(nmarks = (bars / 4) + 1)){
1283                         *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks);
1284                         for (n = 0,   i = current_bbt_points->begin(); i != current_bbt_points->end() && n < nmarks; ++i) {
1285                                 if ((*i).type == TempoMap::Bar)  {
1286                                         if ((*i).bar % 4 == 1) {
1287                                                 if ((*i).bar % 16 == 1) {
1288                                                         snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar);
1289                                                         (*marks)[n].style = GtkCustomRulerMarkMajor;
1290                                                 } else {
1291                                                         snprintf (buf, sizeof(buf), " ");
1292                                                         if ((*i).bar % 16 == 9)  {
1293                                                                 (*marks)[n].style = GtkCustomRulerMarkMinor;
1294                                                         } else {
1295                                                                 (*marks)[n].style = GtkCustomRulerMarkMicro;
1296                                                         }
1297                                                 }
1298                                                 (*marks)[n].label = g_strdup (buf);
1299                                                 (*marks)[n].position = (*i).frame;
1300                                                 n++;
1301                                         }
1302                                 }
1303                         }
1304                 } else {
1305                         nmarks = bars + 1;
1306                         *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks );
1307                         for (n = 0,  i = current_bbt_points->begin(); i != current_bbt_points->end() && n < nmarks; i++) {
1308                                 if ((*i).type == TempoMap::Bar)  {
1309                                         if ((*i).bar % 4 == 1) {
1310                                                 snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar);
1311                                                 (*marks)[n].style = GtkCustomRulerMarkMajor;
1312                                         } else {
1313                                                 snprintf (buf, sizeof(buf), " ");
1314                                                 if ((*i).bar % 4 == 3)  {
1315                                                         (*marks)[n].style = GtkCustomRulerMarkMinor;
1316                                                 } else {
1317                                                         (*marks)[n].style = GtkCustomRulerMarkMicro;
1318                                                 }
1319                                         }
1320                                         (*marks)[n].label = g_strdup (buf);
1321                                         (*marks)[n].position = (*i).frame;
1322                                         n++;
1323                                 }
1324                         }
1325                 }
1326                 return n;
1327         }
1328 }
1329
1330 gint
1331 Editor::metric_get_frames (GtkCustomRulerMark **marks, gdouble lower, gdouble upper, gint maxchars)
1332 {
1333         nframes_t mark_interval;
1334         nframes_t pos;
1335         nframes_t ilower = (nframes_t) floor (lower);
1336         nframes_t iupper = (nframes_t) floor (upper);
1337         gchar buf[16];
1338         gint nmarks;
1339         gint n;
1340
1341         if (session == 0) {
1342                 return 0;
1343         }
1344
1345         mark_interval = (iupper - ilower) / 5;
1346         if (mark_interval > session->frame_rate()) {
1347                 mark_interval -= mark_interval % session->frame_rate();
1348         } else {
1349                 mark_interval = session->frame_rate() / (session->frame_rate() / mark_interval ) ;
1350         }
1351         nmarks = 5;
1352         *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks);
1353         for (n = 0, pos = ilower; n < nmarks; pos += mark_interval, ++n) {
1354                 snprintf (buf, sizeof(buf), "%u", pos);
1355                 (*marks)[n].label = g_strdup (buf);
1356                 (*marks)[n].position = pos;
1357                 (*marks)[n].style = GtkCustomRulerMarkMajor;
1358         }
1359         
1360         return nmarks;
1361 }
1362
1363 static void
1364 sample_to_clock_parts ( nframes_t sample,
1365                         nframes_t sample_rate, 
1366                         long *hrs_p,
1367                         long *mins_p,
1368                         long *secs_p,
1369                         long *millisecs_p)
1370
1371 {
1372         nframes_t left;
1373         long hrs;
1374         long mins;
1375         long secs;
1376         long millisecs;
1377         
1378         left = sample;
1379         hrs = left / (sample_rate * 60 * 60);
1380         left -= hrs * sample_rate * 60 * 60;
1381         mins = left / (sample_rate * 60);
1382         left -= mins * sample_rate * 60;
1383         secs = left / sample_rate;
1384         left -= secs * sample_rate;
1385         millisecs = left * 1000 / sample_rate;
1386
1387         *millisecs_p = millisecs;
1388         *secs_p = secs;
1389         *mins_p = mins;
1390         *hrs_p = hrs;
1391
1392         return;
1393 }
1394
1395 gint
1396 Editor::metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble upper, gint maxchars)
1397 {
1398         nframes_t range;
1399         nframes_t fr;
1400         nframes_t mark_interval;
1401         nframes_t pos;
1402         nframes_t spacer;
1403         long hrs, mins, secs, millisecs;
1404         gchar buf[16];
1405         gint nmarks;
1406         gint n;
1407         gint mark_modulo = 100;
1408         bool show_seconds = false;
1409         bool show_minutes = false;
1410         bool show_hours = false;
1411         nframes_t ilower = (nframes_t) floor (lower);
1412         nframes_t iupper = (nframes_t) floor (upper);
1413
1414         if (session == 0) {
1415                 return 0;
1416         }
1417
1418         fr = session->frame_rate();
1419
1420         /* to prevent 'flashing' */
1421         if (lower > (spacer = (nframes_t)(128 * Editor::get_current_zoom ()))) {
1422                 lower = lower - spacer;
1423         } else {
1424                 lower = 0;
1425         }
1426         upper = upper + spacer;
1427         range = iupper - ilower;
1428
1429         if (range <  (fr / 50)) {
1430                 mark_interval =  fr / 100; /* show 1/100 seconds */
1431                 mark_modulo = 10;
1432         } else if (range <= (fr / 10)) { /* 0-0.1 second */
1433                 mark_interval = fr / 50; /* show 1/50 seconds */
1434                 mark_modulo = 20;
1435         } else if (range <= (fr / 2)) { /* 0-0.5 second */
1436                 mark_interval = fr / 20;  /* show 1/20 seconds */
1437                 mark_modulo = 100;
1438         } else if (range <= fr) { /* 0-1 second */
1439                 mark_interval = fr / 10;  /* show 1/10 seconds */
1440                 mark_modulo = 200;
1441         } else if (range <= 2 * fr) { /* 1-2 seconds */
1442                 mark_interval = fr / 2; /* show 1/2 seconds */
1443                 mark_modulo = 500;
1444         } else if (range <= 8 * fr) { /* 2-5 seconds */
1445                 mark_interval =  fr / 5; /* show 2 seconds */
1446                 mark_modulo = 1000;
1447         } else if (range <= 16 * fr) { /* 8-16 seconds */
1448                 mark_interval =  fr; /* show 1 seconds */
1449                 show_seconds = true;
1450                 mark_modulo = 5;
1451         } else if (range <= 30 * fr) { /* 10-30 seconds */
1452                 mark_interval =  fr; /* show 10 seconds */
1453                 show_seconds = true;
1454                 mark_modulo = 5;
1455         } else if (range <= 60 * fr) { /* 30-60 seconds */
1456                 mark_interval = 5 * fr; /* show 5 seconds */
1457                 show_seconds = true;
1458                 mark_modulo = 3;
1459         } else if (range <= 2 * 60 * fr) { /* 1-2 minutes */
1460                 mark_interval = 5 * fr; /* show 5 seconds */
1461                 show_seconds = true;
1462                 mark_modulo = 3;
1463         } else if (range <= 4 * 60 * fr) { /* 4 minutes */
1464                 mark_interval = 10 * fr; /* show 10 seconds */
1465                 show_seconds = true;
1466                 mark_modulo = 30;
1467         } else if (range <= 10 * 60 * fr) { /* 10 minutes */
1468                 mark_interval = 30 * fr; /* show 30 seconds */
1469                 show_seconds = true;
1470                 mark_modulo = 60;
1471         } else if (range <= 30 * 60 * fr) { /* 10-30 minutes */
1472                 mark_interval =  60 * fr; /* show 1 minute */
1473                 show_minutes = true;
1474                 mark_modulo = 5;
1475         } else if (range <= 60 * 60 * fr) { /* 30 minutes - 1hr */
1476                 mark_interval = 2 * 60 * fr; /* show 2 minutes */
1477                 show_minutes = true;
1478                 mark_modulo = 10;
1479         } else if (range <= 4 * 60 * 60 * fr) { /* 1 - 4 hrs*/
1480                 mark_interval = 5 * 60 * fr; /* show 10 minutes */
1481                 show_minutes = true;
1482                 mark_modulo = 30;
1483         } else if (range <= 8 * 60 * 60 * fr) { /* 4 - 8 hrs*/
1484                 mark_interval = 20 * 60 * fr; /* show 20 minutes */
1485                 show_minutes = true;
1486                 mark_modulo = 60;
1487         } else if (range <= 16 * 60 * 60 * fr) { /* 16-24 hrs*/
1488                 mark_interval =  60 * 60 * fr; /* show 60 minutes */
1489                 show_hours = true;
1490                 mark_modulo = 2;
1491         } else {
1492                                                                                                                    
1493                 /* not possible if nframes_t is a 32 bit quantity */
1494                                                                                                                    
1495                 mark_interval = 4 * 60 * 60 * fr; /* show 4 hrs */
1496         }
1497
1498         nmarks = 1 + (range / mark_interval);
1499         *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks);
1500         pos = ((ilower + (mark_interval/2))/mark_interval) * mark_interval;
1501         
1502         if (show_seconds) {
1503                 for (n = 0; n < nmarks; pos += mark_interval, ++n) {
1504                         sample_to_clock_parts (pos, fr, &hrs, &mins, &secs, &millisecs);
1505                         if (secs % mark_modulo == 0) {
1506                                 if (secs == 0) {
1507                                         (*marks)[n].style = GtkCustomRulerMarkMajor;
1508                                 } else {
1509                                         (*marks)[n].style = GtkCustomRulerMarkMinor;
1510                                 }
1511                                 snprintf (buf, sizeof(buf), "%02ld:%02ld:%02ld.%03ld", hrs, mins, secs, millisecs);
1512                         } else {
1513                                 snprintf (buf, sizeof(buf), " ");
1514                                 (*marks)[n].style = GtkCustomRulerMarkMicro;
1515                         }
1516                         (*marks)[n].label = g_strdup (buf);
1517                         (*marks)[n].position = pos;
1518                 }
1519         } else if (show_minutes) {
1520                 for (n = 0; n < nmarks; pos += mark_interval, ++n) {
1521                         sample_to_clock_parts (pos, fr, &hrs, &mins, &secs, &millisecs);
1522                         if (mins % mark_modulo == 0) {
1523                                 if (mins == 0) {
1524                                         (*marks)[n].style = GtkCustomRulerMarkMajor;
1525                                 } else {
1526                                         (*marks)[n].style = GtkCustomRulerMarkMinor;
1527                                 }
1528                                 snprintf (buf, sizeof(buf), "%02ld:%02ld:%02ld.%03ld", hrs, mins, secs, millisecs);
1529                         } else {
1530                                 snprintf (buf, sizeof(buf), " ");
1531                                 (*marks)[n].style = GtkCustomRulerMarkMicro;
1532                         }
1533                         (*marks)[n].label = g_strdup (buf);
1534                         (*marks)[n].position = pos;
1535                 }
1536         } else if (show_hours) {
1537                  for (n = 0; n < nmarks; pos += mark_interval, ++n) {
1538                         sample_to_clock_parts (pos, fr, &hrs, &mins, &secs, &millisecs);
1539                         if (hrs % mark_modulo == 0) {
1540                                 (*marks)[n].style = GtkCustomRulerMarkMajor;
1541                                 snprintf (buf, sizeof(buf), "%02ld:%02ld:%02ld.%03ld", hrs, mins, secs, millisecs);
1542                         } else {
1543                                 snprintf (buf, sizeof(buf), " ");
1544                                 (*marks)[n].style = GtkCustomRulerMarkMicro;
1545                         }
1546                         (*marks)[n].label = g_strdup (buf);
1547                         (*marks)[n].position = pos;
1548                 }
1549         } else {
1550                 for (n = 0; n < nmarks; pos += mark_interval, ++n) {
1551                         sample_to_clock_parts (pos, fr, &hrs, &mins, &secs, &millisecs);
1552                         if (millisecs % mark_modulo == 0) {
1553                                 if (millisecs == 0) {
1554                                         (*marks)[n].style = GtkCustomRulerMarkMajor;
1555                                 } else {
1556                                         (*marks)[n].style = GtkCustomRulerMarkMinor;
1557                                 }
1558                                 snprintf (buf, sizeof(buf), "%02ld:%02ld:%02ld.%03ld", hrs, mins, secs, millisecs);
1559                         } else {
1560                                 snprintf (buf, sizeof(buf), " ");
1561                                 (*marks)[n].style = GtkCustomRulerMarkMicro;
1562                         }
1563                         (*marks)[n].label = g_strdup (buf);
1564                         (*marks)[n].position = pos;
1565                 }
1566         }
1567
1568         return nmarks;
1569 }