2 Copyright (C) 1999 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.
20 #include <cstdio> // for sprintf
23 #include "pbd/convert.h"
24 #include "pbd/enumwriter.h"
26 #include <gtkmm/style.h>
28 #include "gtkmm2ext/cairocell.h"
29 #include <gtkmm2ext/utils.h>
31 #include "ardour/ardour.h"
32 #include "ardour/session.h"
33 #include "ardour/tempo.h"
34 #include "ardour/profile.h"
35 #include <sigc++/bind.h>
37 #include "ardour_ui.h"
38 #include "audio_clock.h"
41 #include "gui_thread.h"
44 using namespace ARDOUR
;
49 using Gtkmm2ext::Keyboard
;
54 sigc::signal
<void> AudioClock::ModeChanged
;
55 vector
<AudioClock
*> AudioClock::clocks
;
57 uint32_t AudioClock::field_length
[] = {
58 1, /* Timecode_Sign */
59 2, /* Timecode_Hours */
60 2, /* Timecode_Minutes */
61 2, /* Timecode_Seconds */
62 2, /* Timecode_Frames */
66 3, /* MS_Milliseconds */
73 AudioClock::AudioClock (const string
& clock_name
, bool transient
, const string
& widget_name
,
74 bool allow_edit
, bool follows_playhead
, bool duration
, bool with_info
)
76 , is_transient (transient
)
77 , is_duration (duration
)
78 , editable (allow_edit
)
79 , _follows_playhead (follows_playhead
)
81 , supplemental_left (0)
82 , supplemental_right (0)
84 , _canonical_time_is_displayed (true)
97 ms_last_millisecs
= 99999;
99 last_negative
= false;
106 bbt_reference_time
= -1;
107 editing_field
= (Field
) 0;
109 /* basic per-mode editable text "arrays" */
111 display
= new CairoEditableText ();
112 display
->set_corner_radius (0);
114 _fixed_cells
[Colon1
] = new CairoCharCell (Colon1
, ':');
115 _fixed_cells
[Colon2
] = new CairoCharCell (Colon2
, ':');
116 _fixed_cells
[Colon3
] = new CairoCharCell (Colon3
, ':');
117 _fixed_cells
[Bar1
] = new CairoCharCell (Bar1
, '|');
118 _fixed_cells
[Bar2
] = new CairoCharCell (Bar2
, '|');
120 _text_cells
[Timecode_Sign
] = new CairoTextCell (Timecode_Sign
, field_length
[Timecode_Sign
]);
121 _text_cells
[Timecode_Hours
] = new CairoTextCell (Timecode_Hours
, field_length
[Timecode_Hours
]);
122 _text_cells
[Timecode_Minutes
] = new CairoTextCell (Timecode_Minutes
, field_length
[Timecode_Minutes
]);
123 _text_cells
[Timecode_Seconds
] = new CairoTextCell (Timecode_Seconds
, field_length
[Timecode_Seconds
]);
124 _text_cells
[Timecode_Frames
] = new CairoTextCell (Timecode_Frames
, field_length
[Timecode_Frames
]);
126 /* Minutes/Seconds */
128 _text_cells
[MS_Hours
] = new CairoTextCell (MS_Hours
, field_length
[MS_Hours
]);
129 _text_cells
[MS_Minutes
] = new CairoTextCell (MS_Minutes
, field_length
[MS_Minutes
]);
130 _text_cells
[MS_Seconds
] = new CairoTextCell (MS_Seconds
, field_length
[MS_Seconds
]);
131 _text_cells
[MS_Milliseconds
] = new CairoTextCell (MS_Milliseconds
, field_length
[MS_Milliseconds
]);
133 /* Beats/Bars/Ticks */
135 _text_cells
[Bars
] = new CairoTextCell (Bars
, field_length
[Bars
]);
136 _text_cells
[Beats
] = new CairoTextCell (Beats
, field_length
[Beats
]);
137 _text_cells
[Ticks
] = new CairoTextCell (Ticks
, field_length
[Ticks
]);
141 _text_cells
[AudioFrames
] = new CairoTextCell (AudioFrames
, field_length
[AudioFrames
]);
143 set_homogeneous (false);
147 supplemental_left
= new CairoEditableText ();
148 supplemental_right
= new CairoEditableText ();
150 supplemental_left
->set_corner_radius (0);
151 supplemental_right
->set_corner_radius (0);
153 /* field lengths of these cells will be set dynamically by ::set_mode()
156 _text_cells
[LowerLeft1
] = new CairoTextCell (LowerLeft1
, 0);
157 _text_cells
[LowerLeft2
] = new CairoTextCell (LowerLeft2
, 0);
158 _text_cells
[LowerRight1
] = new CairoTextCell (LowerRight1
, 0);
159 _text_cells
[LowerRight2
] = new CairoTextCell (LowerRight2
, 0);
161 bottom
.set_spacing (1);
162 bottom
.set_homogeneous (false);
163 bottom
.pack_start (*supplemental_left
, true, true);
164 bottom
.pack_start (*supplemental_right
, true, true);
166 top
.pack_start (*display
, true, true);
170 pack_start (top
, true, true);
171 pack_start (bottom
, true, true);
173 pack_start (*display
, true, true);
178 set_widget_name (widget_name
);
180 _mode
= BBT
; /* lie to force mode switch */
182 set (last_when
, true);
187 clocks
.push_back (this);
191 AudioClock::~AudioClock ()
193 /* these are not manage()'d, so that we can add/remove
194 them from containers as necessary.
198 delete supplemental_left
;
199 delete supplemental_right
;
201 for (std::map
<Field
,CairoCell
*>::iterator i
= _fixed_cells
.begin(); i
!= _fixed_cells
.end(); ++i
) {
205 for (std::map
<Field
,CairoTextCell
*>::iterator i
= _text_cells
.begin(); i
!= _text_cells
.end(); ++i
) {
211 AudioClock::set_widget_name (const string
& name
)
213 Widget::set_name (name
);
219 AudioClock::set_theme ()
221 Glib::RefPtr
<Gtk::Style
> style
= get_style ();
228 Pango::FontDescription font
;
230 if (!is_realized()) {
231 font
= get_font_for_style (get_name());
233 font
= style
->get_font();
236 display
->set_font (font
);
239 if (supplemental_left
) {
240 /* propagate font style, sort of, into supplemental text */
241 boost::shared_ptr
<CairoFontDescription
> smaller_font (new CairoFontDescription (*display
->font().get()));
242 smaller_font
->set_size (12);
243 smaller_font
->set_weight (Cairo::FONT_WEIGHT_NORMAL
);
244 supplemental_right
->set_font (smaller_font
);
245 supplemental_left
->set_font (smaller_font
);
248 Gdk::Color bg
= style
->get_base (Gtk::STATE_NORMAL
);
249 Gdk::Color fg
= style
->get_text (Gtk::STATE_NORMAL
);
250 Gdk::Color eg
= style
->get_text (Gtk::STATE_ACTIVE
);
253 g
= bg
.get_green_p ();
254 b
= bg
.get_blue_p ();
257 display
->set_bg (r
, g
, b
, a
);
259 if (supplemental_right
) {
260 supplemental_right
->set_bg (r
,g
,b
,a
);
261 supplemental_left
->set_bg (r
,g
,b
,a
);
265 g
= fg
.get_green_p ();
266 b
= fg
.get_blue_p ();
269 display
->set_colors (r
, g
, b
, a
);
271 if (supplemental_right
) {
272 supplemental_right
->set_colors (r
,g
,b
,a
);
273 supplemental_left
->set_colors (r
,g
,b
,a
);
277 g
= eg
.get_green_p ();
278 b
= eg
.get_blue_p ();
281 display
->set_edit_colors (r
, g
, b
, a
);
283 if (supplemental_right
) {
284 supplemental_right
->set_edit_colors (r
,g
,b
,a
);
285 supplemental_left
->set_edit_colors (r
,g
,b
,a
);
297 AudioClock::end_edit ()
299 display
->stop_editing ();
300 editing_field
= (Field
) 0;
303 /* move focus back to the default widget in the top level window */
305 Keyboard::magic_widget_drop_focus ();
307 Widget
* top
= get_toplevel();
309 if (top
->is_toplevel ()) {
310 Window
* win
= dynamic_cast<Window
*> (top
);
316 AudioClock::on_realize ()
320 /* styles are not available until the widgets are bound to a window */
326 AudioClock::set (framepos_t when
, bool force
, framecnt_t offset
, char which
)
328 if ((!force
&& !is_visible()) || _session
== 0) {
332 bool const pdelta
= Config
->get_primary_clock_delta_edit_cursor ();
333 bool const sdelta
= Config
->get_secondary_clock_delta_edit_cursor ();
335 if (offset
&& which
== 'p' && pdelta
) {
336 when
= (when
> offset
) ? when
- offset
: offset
- when
;
337 } else if (offset
&& which
== 's' && sdelta
) {
338 when
= (when
> offset
) ? when
- offset
: offset
- when
;
341 if (when
== last_when
&& !force
) {
345 if (which
== 'p' && pdelta
&& !last_pdelta
) {
346 set_widget_name("TransportClockDisplayDelta");
348 } else if (which
== 'p' && !pdelta
&& last_pdelta
) {
349 set_widget_name("TransportClockDisplay");
351 } else if (which
== 's' && sdelta
&& !last_sdelta
) {
352 set_widget_name("SecondaryClockDisplayDelta");
354 } else if (which
== 's' && !sdelta
&& last_sdelta
) {
355 set_widget_name("SecondaryClockDisplay");
361 set_timecode (when
, force
);
365 set_bbt (when
, force
);
369 set_minsec (when
, force
);
373 set_frames (when
, force
);
379 /* we're setting the time from a frames value, so keep it as the canonical value */
380 _canonical_time
= when
;
381 _canonical_time_is_displayed
= false;
385 AudioClock::session_configuration_changed (std::string p
)
387 if (p
!= "timecode-offset" && p
!= "timecode-offset-negative") {
396 current
= current_duration ();
398 current
= current_time ();
408 AudioClock::set_frames (framepos_t when
, bool /*force*/)
411 snprintf (buf
, sizeof (buf
), "%" PRId64
, when
);
414 display
->set_text (_text_cells
[AudioFrames
], "-----------");
416 if (supplemental_left
) {
417 supplemental_left
->set_text (_text_cells
[LowerLeft2
], "");
418 supplemental_right
->set_text (_text_cells
[LowerRight2
], "");
425 display
->set_text (_text_cells
[AudioFrames
], buf
);
427 if (supplemental_left
) {
428 framecnt_t rate
= _session
->frame_rate();
430 if (fmod (rate
, 1000.0) == 0.000) {
431 sprintf (buf
, "%" PRId64
"K", rate
/1000);
433 sprintf (buf
, "%" PRId64
, rate
);
436 supplemental_left
->set_text (_text_cells
[LowerLeft2
], buf
);
438 float vid_pullup
= _session
->config
.get_video_pullup();
440 if (vid_pullup
== 0.0) {
441 supplemental_right
->set_text (_text_cells
[LowerRight2
], _("none"));
443 sprintf (buf
, "%-6.4f", vid_pullup
);
444 supplemental_right
->set_text (_text_cells
[LowerRight2
], buf
);
450 AudioClock::set_minsec (framepos_t when
, bool force
)
460 display
->set_text (_text_cells
[MS_Hours
], "--");
461 display
->set_text (_text_cells
[MS_Minutes
], "--");
462 display
->set_text (_text_cells
[MS_Seconds
], "--");
463 display
->set_text (_text_cells
[MS_Milliseconds
], "--");
465 if (supplemental_left
) {
466 supplemental_left
->set_text (_text_cells
[LowerLeft2
], "");
467 supplemental_right
->set_text (_text_cells
[LowerRight2
], "");
474 hrs
= (int) floor (left
/ (_session
->frame_rate() * 60.0f
* 60.0f
));
475 left
-= (framecnt_t
) floor (hrs
* _session
->frame_rate() * 60.0f
* 60.0f
);
476 mins
= (int) floor (left
/ (_session
->frame_rate() * 60.0f
));
477 left
-= (framecnt_t
) floor (mins
* _session
->frame_rate() * 60.0f
);
478 secs
= (int) floor (left
/ (float) _session
->frame_rate());
479 left
-= (framecnt_t
) floor (secs
* _session
->frame_rate());
480 millisecs
= floor (left
* 1000.0 / (float) _session
->frame_rate());
482 if (force
|| hrs
!= ms_last_hrs
) {
483 sprintf (buf
, "%02d", hrs
);
484 display
->set_text (_text_cells
[MS_Hours
], buf
);
488 if (force
|| mins
!= ms_last_mins
) {
489 sprintf (buf
, "%02d", mins
);
490 display
->set_text (_text_cells
[MS_Minutes
], buf
);
494 if (force
|| secs
!= ms_last_secs
) {
495 sprintf (buf
, "%02d", secs
);
496 display
->set_text (_text_cells
[MS_Seconds
], buf
);
500 if (force
|| millisecs
!= ms_last_millisecs
) {
501 sprintf (buf
, "%03d", millisecs
);
502 display
->set_text (_text_cells
[MS_Milliseconds
], buf
);
503 ms_last_millisecs
= millisecs
;
508 AudioClock::set_timecode (framepos_t when
, bool force
)
514 display
->set_text (_text_cells
[Timecode_Sign
], "");
515 display
->set_text (_text_cells
[Timecode_Hours
], "--");
516 display
->set_text (_text_cells
[Timecode_Minutes
], "--");
517 display
->set_text (_text_cells
[Timecode_Seconds
], "--");
518 display
->set_text (_text_cells
[Timecode_Frames
], "--");
520 if (supplemental_left
) {
521 supplemental_left
->set_text (_text_cells
[LowerLeft2
], "");
522 supplemental_right
->set_text (_text_cells
[LowerRight2
], "");
529 _session
->timecode_duration (when
, TC
);
531 _session
->timecode_time (when
, TC
);
534 if (force
|| TC
.hours
!= last_hrs
|| TC
.negative
!= last_negative
) {
536 display
->set_text (_text_cells
[Timecode_Sign
], "-");
537 sprintf (buf
, "%0*" PRIu32
, field_length
[Timecode_Hours
], TC
.hours
);
539 display
->set_text (_text_cells
[Timecode_Sign
], " ");
540 sprintf (buf
, "%0*" PRIu32
, field_length
[Timecode_Hours
], TC
.hours
);
542 display
->set_text (_text_cells
[Timecode_Hours
], buf
);
544 last_negative
= TC
.negative
;
547 if (force
|| TC
.minutes
!= last_mins
) {
548 sprintf (buf
, "%0*" PRIu32
, field_length
[Timecode_Minutes
], TC
.minutes
);
549 display
->set_text (_text_cells
[Timecode_Minutes
], buf
);
550 last_mins
= TC
.minutes
;
553 if (force
|| TC
.seconds
!= last_secs
) {
554 sprintf (buf
, "%0*" PRIu32
, field_length
[Timecode_Seconds
], TC
.seconds
);
555 display
->set_text (_text_cells
[Timecode_Seconds
], buf
);
556 last_secs
= TC
.seconds
;
559 if (force
|| TC
.frames
!= last_frames
) {
560 sprintf (buf
, "%0*" PRIu32
, field_length
[Timecode_Frames
], TC
.frames
);
561 display
->set_text (_text_cells
[Timecode_Frames
], buf
);
562 last_frames
= TC
.frames
;
565 if (supplemental_right
) {
566 double timecode_frames
= _session
->timecode_frames_per_second();
568 if (fmod(timecode_frames
, 1.0) == 0.0) {
569 sprintf (buf
, "%u %s", int (timecode_frames
), (_session
->timecode_drop_frames() ? "D" : ""));
571 sprintf (buf
, "%.2f %s", timecode_frames
, (_session
->timecode_drop_frames() ? "D" : ""));
574 supplemental_right
->set_text (_text_cells
[LowerRight2
], buf
);
579 AudioClock::set_bbt (framepos_t when
, bool force
)
582 Timecode::BBT_Time BBT
;
585 display
->set_text (_text_cells
[Bars
], "--");
586 display
->set_text (_text_cells
[Beats
], "--");
587 display
->set_text (_text_cells
[Ticks
], "--");
589 if (supplemental_left
) {
590 supplemental_left
->set_text (_text_cells
[LowerLeft2
], "");
591 supplemental_right
->set_text (_text_cells
[LowerRight2
], "");
597 /* handle a common case */
604 _session
->tempo_map().bbt_time (when
, BBT
);
609 _session
->tempo_map().bbt_time (when
, BBT
);
612 sprintf (buf
, "%0*" PRIu32
, field_length
[Bars
], BBT
.bars
);
613 if (force
|| _text_cells
[Bars
]->get_text () != buf
) {
614 display
->set_text (_text_cells
[Bars
], buf
);
616 sprintf (buf
, "%0*" PRIu32
, field_length
[Beats
], BBT
.beats
);
617 if (force
|| _text_cells
[Beats
]->get_text () != buf
) {
618 display
->set_text (_text_cells
[Beats
], buf
);
620 sprintf (buf
, "%0*" PRIu32
, field_length
[Ticks
], BBT
.ticks
);
621 if (force
|| _text_cells
[Ticks
]->get_text () != buf
) {
622 display
->set_text (_text_cells
[Ticks
], buf
);
625 if (supplemental_right
) {
628 if (bbt_reference_time
< 0) {
631 pos
= bbt_reference_time
;
634 TempoMetric
m (_session
->tempo_map().metric_at (pos
));
636 sprintf (buf
, "%-5.2f", m
.tempo().beats_per_minute());
637 supplemental_left
->set_text (_text_cells
[LowerLeft2
], buf
);
639 sprintf (buf
, "%g|%g", m
.meter().beats_per_bar(), m
.meter().note_divisor());
640 supplemental_right
->set_text (_text_cells
[LowerRight2
], buf
);
645 AudioClock::set_session (Session
*s
)
647 SessionHandlePtr::set_session (s
);
651 _session
->config
.ParameterChanged
.connect (_session_connections
, invalidator (*this), boost::bind (&AudioClock::session_configuration_changed
, this, _1
), gui_context());
653 const XMLProperty
* prop
;
654 XMLNode
* node
= _session
->extra_xml (X_("ClockModes"));
655 AudioClock::Mode amode
;
658 for (XMLNodeList::const_iterator i
= node
->children().begin(); i
!= node
->children().end(); ++i
) {
659 if ((prop
= (*i
)->property (X_("name"))) && prop
->value() == _name
) {
661 if ((prop
= (*i
)->property (X_("mode"))) != 0) {
662 amode
= AudioClock::Mode (string_2_enum (prop
->value(), amode
));
665 if ((prop
= (*i
)->property (X_("on"))) != 0) {
666 set_off (!string_is_affirmative (prop
->value()));
673 set (last_when
, true);
678 AudioClock::edit_next_field ()
680 /* move on to the next field.
683 switch (editing_field
) {
688 editing_field
= Timecode_Minutes
;
689 display
->start_editing (_text_cells
[Timecode_Minutes
]);
691 case Timecode_Minutes
:
692 editing_field
= Timecode_Seconds
;
693 display
->start_editing (_text_cells
[Timecode_Seconds
]);
695 case Timecode_Seconds
:
696 editing_field
= Timecode_Frames
;
697 display
->start_editing (_text_cells
[Timecode_Frames
]);
699 case Timecode_Frames
:
706 editing_field
= MS_Minutes
;
707 display
->start_editing (_text_cells
[MS_Minutes
]);
710 editing_field
= MS_Seconds
;
711 display
->start_editing (_text_cells
[MS_Seconds
]);
714 editing_field
= MS_Milliseconds
;
715 display
->start_editing (_text_cells
[MS_Milliseconds
]);
717 case MS_Milliseconds
:
724 editing_field
= Beats
;
725 display
->start_editing (_text_cells
[Beats
]);
728 editing_field
= Ticks
;
729 display
->start_editing (_text_cells
[Ticks
]);
748 AudioClock::on_key_press_event (GdkEventKey
* ev
)
750 /* return true for keys that we MIGHT use
753 switch (ev
->keyval
) {
788 AudioClock::on_key_release_event (GdkEventKey
*ev
)
790 if (editing_field
== 0) {
794 CairoTextCell
*cell
= _text_cells
[editing_field
];
802 bool move_on
= false;
804 switch (ev
->keyval
) {
849 if (_mode
== MinSec
&& editing_field
== MS_Seconds
) {
850 new_char
= '.'; // XXX i18n
864 ChangeAborted(); /* EMIT SIGNAL */
873 if (key_entry_state
== 0) {
875 /* initialize with a fresh new string */
877 if (editing_field
!= AudioFrames
) {
878 for (uint32_t xn
= 0; xn
< field_length
[editing_field
] - 1; ++xn
) {
887 string existing
= cell
->get_text();
888 if (existing
.length() >= field_length
[editing_field
]) {
889 new_text
= existing
.substr (1, field_length
[editing_field
] - 1);
891 new_text
= existing
.substr (0, field_length
[editing_field
] - 1);
895 new_text
+= new_char
;
896 display
->set_text (cell
, new_text
);
897 _canonical_time_is_displayed
= true;
901 if (key_entry_state
== field_length
[editing_field
]) {
907 if (key_entry_state
) {
909 /* if key_entry_state != then we edited the text
914 switch (editing_field
) {
916 case Timecode_Minutes
:
917 case Timecode_Seconds
:
918 case Timecode_Frames
:
919 // Check Timecode fields for sanity (may also adjust fields)
920 timecode_sanitize_display();
925 // Bars should never be zero, unless this clock is for a duration
926 if (atoi (_text_cells
[Bars
]->get_text()) == 0 && !is_duration
) {
927 snprintf (buf
, sizeof (buf
), "%0*" PRIu32
, field_length
[Bars
], 1);
928 display
->set_text (_text_cells
[Bars
], buf
);
929 _canonical_time_is_displayed
= true;
931 // beats should never be zero, unless this clock is for a duration
932 if (atoi (_text_cells
[Beats
]->get_text()) == 0 && !is_duration
) {
933 snprintf (buf
, sizeof (buf
), "%0*" PRIu32
, field_length
[Beats
], 1);
934 display
->set_text (_text_cells
[Beats
], buf
);
935 _canonical_time_is_displayed
= true;
942 ValueChanged(); /* EMIT_SIGNAL */
948 //if user hit Enter, lose focus
949 switch (ev
->keyval
) {
959 AudioClock::button_press (GdkEventButton
*ev
, CairoCell
* cell
)
961 switch (ev
->button
) {
965 Field f
= (Field
) cell
->id ();
968 case Timecode_Minutes
:
969 case Timecode_Seconds
:
970 case Timecode_Frames
:
974 case MS_Milliseconds
:
980 display
->start_editing (cell
);
987 Keyboard::magic_widget_grab_focus ();
989 /* make absolutely sure that the pointer is grabbed */
990 gdk_pointer_grab(ev
->window
,false ,
991 GdkEventMask( Gdk::POINTER_MOTION_MASK
| Gdk::BUTTON_PRESS_MASK
|Gdk::BUTTON_RELEASE_MASK
),
995 drag_start_y
= ev
->y
;
1009 AudioClock::button_release (GdkEventButton
*ev
, CairoCell
* cell
)
1013 gdk_pointer_ungrab (GDK_CURRENT_TIME
);
1015 if (ev
->y
> drag_start_y
+1 || ev
->y
< drag_start_y
-1 || Keyboard::modifier_state_equals (ev
->state
, Keyboard::TertiaryModifier
)){
1016 // we actually dragged so return without setting editing focus, or we shift clicked
1022 if (Keyboard::is_context_menu_event (ev
)) {
1023 if (ops_menu
== 0) {
1026 ops_menu
->popup (1, ev
->time
);
1034 AudioClock::scroll (GdkEventScroll
*ev
, CairoCell
* cell
)
1036 if (_session
== 0 || !editable
) {
1041 Field f
= (Field
) cell
->id ();
1043 case Timecode_Hours
:
1044 case Timecode_Minutes
:
1045 case Timecode_Seconds
:
1046 case Timecode_Frames
:
1050 case MS_Milliseconds
:
1061 framepos_t frames
= 0;
1063 switch (ev
->direction
) {
1066 frames
= get_frames ((Field
) cell
->id());
1068 if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::PrimaryModifier
)) {
1071 set (current_time() + frames
, true);
1072 ValueChanged (); /* EMIT_SIGNAL */
1076 case GDK_SCROLL_DOWN
:
1077 frames
= get_frames ((Field
) cell
->id());
1079 if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::PrimaryModifier
)) {
1083 if ((double)current_time() - (double)frames
< 0.0) {
1086 set (current_time() - frames
, true);
1089 ValueChanged (); /* EMIT_SIGNAL */
1102 AudioClock::field_motion_notify_event (GdkEventMotion
*ev
, Field field
)
1104 if (_session
== 0 || !dragging
) {
1108 float pixel_frame_scale_factor
= 0.2f
;
1111 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1112 pixel_frame_scale_factor = 0.1f;
1116 if (Keyboard::modifier_state_contains (ev->state,
1117 Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)) {
1119 pixel_frame_scale_factor = 0.025f;
1122 double y_delta
= ev
->y
- drag_y
;
1124 drag_accum
+= y_delta
*pixel_frame_scale_factor
;
1128 if (trunc(drag_accum
) != 0) {
1133 dir
= (drag_accum
< 0 ? 1:-1);
1134 pos
= current_time();
1135 frames
= get_frames (field
,pos
,dir
);
1137 if (frames
!= 0 && frames
* drag_accum
< current_time()) {
1139 set ((framepos_t
) floor (pos
- drag_accum
* frames
), false); // minus because up is negative in computer-land
1147 ValueChanged(); /* EMIT_SIGNAL */
1156 AudioClock::get_frames (Field field
, framepos_t pos
, int dir
)
1159 Timecode::BBT_Time BBT
;
1161 case Timecode_Hours
:
1162 f
= (framecnt_t
) floor (3600.0 * _session
->frame_rate());
1164 case Timecode_Minutes
:
1165 f
= (framecnt_t
) floor (60.0 * _session
->frame_rate());
1167 case Timecode_Seconds
:
1168 f
= _session
->frame_rate();
1170 case Timecode_Frames
:
1171 f
= (framecnt_t
) floor (_session
->frame_rate() / _session
->timecode_frames_per_second());
1179 f
= (framecnt_t
) floor (3600.0 * _session
->frame_rate());
1182 f
= (framecnt_t
) floor (60.0 * _session
->frame_rate());
1185 f
= (framecnt_t
) _session
->frame_rate();
1187 case MS_Milliseconds
:
1188 f
= (framecnt_t
) floor (_session
->frame_rate() / 1000.0);
1195 f
= _session
->tempo_map().bbt_duration_at (pos
,BBT
,dir
);
1201 f
= _session
->tempo_map().bbt_duration_at(pos
,BBT
,dir
);
1207 f
= _session
->tempo_map().bbt_duration_at(pos
,BBT
,dir
);
1210 error
<< string_compose (_("programming error: %1"), "attempt to get frames from non-text field!") << endmsg
;
1219 AudioClock::current_time (framepos_t pos
) const
1221 if (!_canonical_time_is_displayed
) {
1222 return _canonical_time
;
1229 ret
= timecode_frame_from_display ();
1232 ret
= bbt_frame_from_display (pos
);
1236 ret
= minsec_frame_from_display ();
1240 ret
= audio_frame_from_display ();
1248 AudioClock::current_duration (framepos_t pos
) const
1254 ret
= timecode_frame_from_display ();
1257 ret
= bbt_frame_duration_from_display (pos
);
1261 ret
= minsec_frame_from_display ();
1265 ret
= audio_frame_from_display ();
1273 AudioClock::timecode_sanitize_display()
1275 // Check Timecode fields for sanity, possibly adjusting values
1276 if (atoi (_text_cells
[Timecode_Minutes
]->get_text()) > 59) {
1277 display
->set_text (_text_cells
[Timecode_Minutes
], "59");
1278 _canonical_time_is_displayed
= true;
1281 if (atoi (_text_cells
[Timecode_Seconds
]->get_text()) > 59) {
1282 display
->set_text (_text_cells
[Timecode_Seconds
], "59");
1283 _canonical_time_is_displayed
= true;
1286 switch ((long)rint(_session
->timecode_frames_per_second())) {
1288 if (atoi (_text_cells
[Timecode_Frames
]->get_text()) > 23) {
1289 display
->set_text (_text_cells
[Timecode_Frames
], "23");
1290 _canonical_time_is_displayed
= true;
1294 if (atoi (_text_cells
[Timecode_Frames
]->get_text()) > 24) {
1295 display
->set_text (_text_cells
[Timecode_Frames
], "24");
1296 _canonical_time_is_displayed
= true;
1300 if (atoi (_text_cells
[Timecode_Frames
]->get_text()) > 29) {
1301 display
->set_text (_text_cells
[Timecode_Frames
], "29");
1302 _canonical_time_is_displayed
= true;
1309 if (_session
->timecode_drop_frames()) {
1310 if ((atoi (_text_cells
[Timecode_Minutes
]->get_text()) % 10) && (atoi (_text_cells
[Timecode_Seconds
]->get_text()) == 0) && (atoi (_text_cells
[Timecode_Frames
]->get_text()) < 2)) {
1311 display
->set_text (_text_cells
[Timecode_Frames
], "02");
1312 _canonical_time_is_displayed
= true;
1317 /** This is necessary because operator[] isn't const with std::map.
1319 * @return Label widget.
1322 AudioClock::label (Field f
) const
1324 std::map
<Field
,CairoTextCell
*>::const_iterator i
= _text_cells
.find (f
);
1325 assert (i
!= _text_cells
.end ());
1331 AudioClock::timecode_frame_from_display () const
1333 if (_session
== 0) {
1340 if (!label (Timecode_Sign
)->get_text().empty()) {
1341 TC
.hours
= atoi (label (Timecode_Hours
)->get_text());
1343 TC
.hours
= -atoi (label (Timecode_Hours
)->get_text());
1346 TC
.minutes
= atoi (label (Timecode_Minutes
)->get_text());
1347 TC
.seconds
= atoi (label (Timecode_Seconds
)->get_text());
1348 TC
.frames
= atoi (label (Timecode_Frames
)->get_text());
1349 TC
.rate
= _session
->timecode_frames_per_second();
1350 TC
.drop
= _session
->timecode_drop_frames();
1352 _session
->timecode_to_sample (TC
, sample
, false /* use_offset */, false /* use_subframes */ );
1356 #define Timecode_SAMPLE_TEST_1
1357 #define Timecode_SAMPLE_TEST_2
1358 #define Timecode_SAMPLE_TEST_3
1359 #define Timecode_SAMPLE_TEST_4
1360 #define Timecode_SAMPLE_TEST_5
1361 #define Timecode_SAMPLE_TEST_6
1362 #define Timecode_SAMPLE_TEST_7
1364 // Testcode for timecode<->sample conversions (P.S.)
1365 Timecode::Time timecode1
;
1367 framepos_t oldsample
= 0;
1368 Timecode::Time timecode2
;
1369 framecnt_t sample_increment
;
1371 sample_increment
= (framecnt_t
)rint(_session
->frame_rate() / _session
->timecode_frames_per_second
);
1373 #ifdef Timecode_SAMPLE_TEST_1
1374 // Test 1: use_offset = false, use_subframes = false
1375 cout
<< "use_offset = false, use_subframes = false" << endl
;
1376 for (int i
= 0; i
< 108003; i
++) {
1377 _session
->timecode_to_sample( timecode1
, sample1
, false /* use_offset */, false /* use_subframes */ );
1378 _session
->sample_to_timecode( sample1
, timecode2
, false /* use_offset */, false /* use_subframes */ );
1380 if ((i
> 0) && ( ((sample1
- oldsample
) != sample_increment
) && ((sample1
- oldsample
) != (sample_increment
+ 1)) && ((sample1
- oldsample
) != (sample_increment
- 1)))) {
1381 cout
<< "ERROR: sample increment not right: " << (sample1
- oldsample
) << " != " << sample_increment
<< endl
;
1382 cout
<< "timecode1: " << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1383 cout
<< "sample: " << sample1
<< endl
;
1384 cout
<< "sample: " << sample1
<< " -> ";
1385 cout
<< "timecode2: " << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1389 if (timecode2
.hours
!= timecode1
.hours
|| timecode2
.minutes
!= timecode1
.minutes
|| timecode2
.seconds
!= timecode2
.seconds
|| timecode2
.frames
!= timecode1
.frames
) {
1390 cout
<< "ERROR: timecode2 not equal timecode1" << endl
;
1391 cout
<< "timecode1: " << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1392 cout
<< "sample: " << sample1
<< endl
;
1393 cout
<< "sample: " << sample1
<< " -> ";
1394 cout
<< "timecode2: " << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1397 oldsample
= sample1
;
1398 _session
->timecode_increment( timecode1
);
1401 cout
<< "sample_increment: " << sample_increment
<< endl
;
1402 cout
<< "sample: " << sample1
<< " -> ";
1403 cout
<< "timecode: " << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1406 #ifdef Timecode_SAMPLE_TEST_2
1407 // Test 2: use_offset = true, use_subframes = false
1408 cout
<< "use_offset = true, use_subframes = false" << endl
;
1410 timecode1
.hours
= 0;
1411 timecode1
.minutes
= 0;
1412 timecode1
.seconds
= 0;
1413 timecode1
.frames
= 0;
1414 timecode1
.subframes
= 0;
1415 sample1
= oldsample
= 0;
1417 _session
->sample_to_timecode( sample1
, timecode1
, true /* use_offset */, false /* use_subframes */ );
1418 cout
<< "Starting at sample: " << sample1
<< " -> ";
1419 cout
<< "timecode: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< endl
;
1421 for (int i
= 0; i
< 108003; i
++) {
1422 _session
->timecode_to_sample( timecode1
, sample1
, true /* use_offset */, false /* use_subframes */ );
1423 _session
->sample_to_timecode( sample1
, timecode2
, true /* use_offset */, false /* use_subframes */ );
1425 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1426 // cout << "sample: " << sample1 << endl;
1427 // cout << "sample: " << sample1 << " -> ";
1428 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1430 if ((i
> 0) && ( ((sample1
- oldsample
) != sample_increment
) && ((sample1
- oldsample
) != (sample_increment
+ 1)) && ((sample1
- oldsample
) != (sample_increment
- 1)))) {
1431 cout
<< "ERROR: sample increment not right: " << (sample1
- oldsample
) << " != " << sample_increment
<< endl
;
1432 cout
<< "timecode1: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1433 cout
<< "sample: " << sample1
<< endl
;
1434 cout
<< "sample: " << sample1
<< " -> ";
1435 cout
<< "timecode2: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1439 if (timecode2
.hours
!= timecode1
.hours
|| timecode2
.minutes
!= timecode1
.minutes
|| timecode2
.seconds
!= timecode2
.seconds
|| timecode2
.frames
!= timecode1
.frames
) {
1440 cout
<< "ERROR: timecode2 not equal timecode1" << endl
;
1441 cout
<< "timecode1: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1442 cout
<< "sample: " << sample1
<< endl
;
1443 cout
<< "sample: " << sample1
<< " -> ";
1444 cout
<< "timecode2: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1447 oldsample
= sample1
;
1448 _session
->timecode_increment( timecode1
);
1451 cout
<< "sample_increment: " << sample_increment
<< endl
;
1452 cout
<< "sample: " << sample1
<< " -> ";
1453 cout
<< "timecode: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1456 #ifdef Timecode_SAMPLE_TEST_3
1457 // Test 3: use_offset = true, use_subframes = false, decrement
1458 cout
<< "use_offset = true, use_subframes = false, decrement" << endl
;
1460 _session
->sample_to_timecode( sample1
, timecode1
, true /* use_offset */, false /* use_subframes */ );
1461 cout
<< "Starting at sample: " << sample1
<< " -> ";
1462 cout
<< "timecode: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< endl
;
1464 for (int i
= 0; i
< 108003; i
++) {
1465 _session
->timecode_to_sample( timecode1
, sample1
, true /* use_offset */, false /* use_subframes */ );
1466 _session
->sample_to_timecode( sample1
, timecode2
, true /* use_offset */, false /* use_subframes */ );
1468 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1469 // cout << "sample: " << sample1 << endl;
1470 // cout << "sample: " << sample1 << " -> ";
1471 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1473 if ((i
> 0) && ( ((oldsample
- sample1
) != sample_increment
) && ((oldsample
- sample1
) != (sample_increment
+ 1)) && ((oldsample
- sample1
) != (sample_increment
- 1)))) {
1474 cout
<< "ERROR: sample increment not right: " << (oldsample
- sample1
) << " != " << sample_increment
<< endl
;
1475 cout
<< "timecode1: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1476 cout
<< "sample: " << sample1
<< endl
;
1477 cout
<< "sample: " << sample1
<< " -> ";
1478 cout
<< "timecode2: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1482 if (timecode2
.hours
!= timecode1
.hours
|| timecode2
.minutes
!= timecode1
.minutes
|| timecode2
.seconds
!= timecode2
.seconds
|| timecode2
.frames
!= timecode1
.frames
) {
1483 cout
<< "ERROR: timecode2 not equal timecode1" << endl
;
1484 cout
<< "timecode1: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1485 cout
<< "sample: " << sample1
<< endl
;
1486 cout
<< "sample: " << sample1
<< " -> ";
1487 cout
<< "timecode2: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1490 oldsample
= sample1
;
1491 _session
->timecode_decrement( timecode1
);
1494 cout
<< "sample_decrement: " << sample_increment
<< endl
;
1495 cout
<< "sample: " << sample1
<< " -> ";
1496 cout
<< "timecode: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1500 #ifdef Timecode_SAMPLE_TEST_4
1501 // Test 4: use_offset = true, use_subframes = true
1502 cout
<< "use_offset = true, use_subframes = true" << endl
;
1504 for (long sub
= 5; sub
< 80; sub
+= 5) {
1505 timecode1
.hours
= 0;
1506 timecode1
.minutes
= 0;
1507 timecode1
.seconds
= 0;
1508 timecode1
.frames
= 0;
1509 timecode1
.subframes
= 0;
1510 sample1
= oldsample
= (sample_increment
* sub
) / 80;
1512 _session
->sample_to_timecode( sample1
, timecode1
, true /* use_offset */, true /* use_subframes */ );
1514 cout
<< "starting at sample: " << sample1
<< " -> ";
1515 cout
<< "timecode: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< endl
;
1517 for (int i
= 0; i
< 108003; i
++) {
1518 _session
->timecode_to_sample( timecode1
, sample1
, true /* use_offset */, true /* use_subframes */ );
1519 _session
->sample_to_timecode( sample1
, timecode2
, true /* use_offset */, true /* use_subframes */ );
1521 if ((i
> 0) && ( ((sample1
- oldsample
) != sample_increment
) && ((sample1
- oldsample
) != (sample_increment
+ 1)) && ((sample1
- oldsample
) != (sample_increment
- 1)))) {
1522 cout
<< "ERROR: sample increment not right: " << (sample1
- oldsample
) << " != " << sample_increment
<< endl
;
1523 cout
<< "timecode1: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1524 cout
<< "sample: " << sample1
<< endl
;
1525 cout
<< "sample: " << sample1
<< " -> ";
1526 cout
<< "timecode2: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1530 if (timecode2
.hours
!= timecode1
.hours
|| timecode2
.minutes
!= timecode1
.minutes
|| timecode2
.seconds
!= timecode2
.seconds
|| timecode2
.frames
!= timecode1
.frames
|| timecode2
.subframes
!= timecode1
.subframes
) {
1531 cout
<< "ERROR: timecode2 not equal timecode1" << endl
;
1532 cout
<< "timecode1: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1533 cout
<< "sample: " << sample1
<< endl
;
1534 cout
<< "sample: " << sample1
<< " -> ";
1535 cout
<< "timecode2: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1538 oldsample
= sample1
;
1539 _session
->timecode_increment( timecode1
);
1542 cout
<< "sample_increment: " << sample_increment
<< endl
;
1543 cout
<< "sample: " << sample1
<< " -> ";
1544 cout
<< "timecode: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1546 for (int i
= 0; i
< 108003; i
++) {
1547 _session
->timecode_to_sample( timecode1
, sample1
, true /* use_offset */, true /* use_subframes */ );
1548 _session
->sample_to_timecode( sample1
, timecode2
, true /* use_offset */, true /* use_subframes */ );
1550 if ((i
> 0) && ( ((oldsample
- sample1
) != sample_increment
) && ((oldsample
- sample1
) != (sample_increment
+ 1)) && ((oldsample
- sample1
) != (sample_increment
- 1)))) {
1551 cout
<< "ERROR: sample increment not right: " << (oldsample
- sample1
) << " != " << sample_increment
<< endl
;
1552 cout
<< "timecode1: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1553 cout
<< "sample: " << sample1
<< endl
;
1554 cout
<< "sample: " << sample1
<< " -> ";
1555 cout
<< "timecode2: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1559 if (timecode2
.hours
!= timecode1
.hours
|| timecode2
.minutes
!= timecode1
.minutes
|| timecode2
.seconds
!= timecode2
.seconds
|| timecode2
.frames
!= timecode1
.frames
|| timecode2
.subframes
!= timecode1
.subframes
) {
1560 cout
<< "ERROR: timecode2 not equal timecode1" << endl
;
1561 cout
<< "timecode1: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1562 cout
<< "sample: " << sample1
<< endl
;
1563 cout
<< "sample: " << sample1
<< " -> ";
1564 cout
<< "timecode2: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1567 oldsample
= sample1
;
1568 _session
->timecode_decrement( timecode1
);
1571 cout
<< "sample_decrement: " << sample_increment
<< endl
;
1572 cout
<< "sample: " << sample1
<< " -> ";
1573 cout
<< "timecode: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1578 #ifdef Timecode_SAMPLE_TEST_5
1579 // Test 5: use_offset = true, use_subframes = false, increment seconds
1580 cout
<< "use_offset = true, use_subframes = false, increment seconds" << endl
;
1582 timecode1
.hours
= 0;
1583 timecode1
.minutes
= 0;
1584 timecode1
.seconds
= 0;
1585 timecode1
.frames
= 0;
1586 timecode1
.subframes
= 0;
1587 sample1
= oldsample
= 0;
1588 sample_increment
= _session
->frame_rate();
1590 _session
->sample_to_timecode( sample1
, timecode1
, true /* use_offset */, false /* use_subframes */ );
1591 cout
<< "Starting at sample: " << sample1
<< " -> ";
1592 cout
<< "timecode: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< endl
;
1594 for (int i
= 0; i
< 3600; i
++) {
1595 _session
->timecode_to_sample( timecode1
, sample1
, true /* use_offset */, false /* use_subframes */ );
1596 _session
->sample_to_timecode( sample1
, timecode2
, true /* use_offset */, false /* use_subframes */ );
1598 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1599 // cout << "sample: " << sample1 << endl;
1600 // cout << "sample: " << sample1 << " -> ";
1601 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1603 // if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1))))
1605 // cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1609 if (timecode2
.hours
!= timecode1
.hours
|| timecode2
.minutes
!= timecode1
.minutes
|| timecode2
.seconds
!= timecode2
.seconds
|| timecode2
.frames
!= timecode1
.frames
) {
1610 cout
<< "ERROR: timecode2 not equal timecode1" << endl
;
1611 cout
<< "timecode: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1612 cout
<< "sample: " << sample1
<< endl
;
1613 cout
<< "sample: " << sample1
<< " -> ";
1614 cout
<< "timecode: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1617 oldsample
= sample1
;
1618 _session
->timecode_increment_seconds( timecode1
);
1621 cout
<< "sample_increment: " << sample_increment
<< endl
;
1622 cout
<< "sample: " << sample1
<< " -> ";
1623 cout
<< "timecode: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1627 #ifdef Timecode_SAMPLE_TEST_6
1628 // Test 6: use_offset = true, use_subframes = false, increment minutes
1629 cout
<< "use_offset = true, use_subframes = false, increment minutes" << endl
;
1631 timecode1
.hours
= 0;
1632 timecode1
.minutes
= 0;
1633 timecode1
.seconds
= 0;
1634 timecode1
.frames
= 0;
1635 timecode1
.subframes
= 0;
1636 sample1
= oldsample
= 0;
1637 sample_increment
= _session
->frame_rate() * 60;
1639 _session
->sample_to_timecode( sample1
, timecode1
, true /* use_offset */, false /* use_subframes */ );
1640 cout
<< "Starting at sample: " << sample1
<< " -> ";
1641 cout
<< "timecode: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< endl
;
1643 for (int i
= 0; i
< 60; i
++) {
1644 _session
->timecode_to_sample( timecode1
, sample1
, true /* use_offset */, false /* use_subframes */ );
1645 _session
->sample_to_timecode( sample1
, timecode2
, true /* use_offset */, false /* use_subframes */ );
1647 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1648 // cout << "sample: " << sample1 << endl;
1649 // cout << "sample: " << sample1 << " -> ";
1650 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1652 // if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1))))
1654 // cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1658 if (timecode2
.hours
!= timecode1
.hours
|| timecode2
.minutes
!= timecode1
.minutes
|| timecode2
.seconds
!= timecode2
.seconds
|| timecode2
.frames
!= timecode1
.frames
) {
1659 cout
<< "ERROR: timecode2 not equal timecode1" << endl
;
1660 cout
<< "timecode: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1661 cout
<< "sample: " << sample1
<< endl
;
1662 cout
<< "sample: " << sample1
<< " -> ";
1663 cout
<< "timecode: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1666 oldsample
= sample1
;
1667 _session
->timecode_increment_minutes( timecode1
);
1670 cout
<< "sample_increment: " << sample_increment
<< endl
;
1671 cout
<< "sample: " << sample1
<< " -> ";
1672 cout
<< "timecode: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1675 #ifdef Timecode_SAMPLE_TEST_7
1676 // Test 7: use_offset = true, use_subframes = false, increment hours
1677 cout
<< "use_offset = true, use_subframes = false, increment hours" << endl
;
1679 timecode1
.hours
= 0;
1680 timecode1
.minutes
= 0;
1681 timecode1
.seconds
= 0;
1682 timecode1
.frames
= 0;
1683 timecode1
.subframes
= 0;
1684 sample1
= oldsample
= 0;
1685 sample_increment
= _session
->frame_rate() * 60 * 60;
1687 _session
->sample_to_timecode( sample1
, timecode1
, true /* use_offset */, false /* use_subframes */ );
1688 cout
<< "Starting at sample: " << sample1
<< " -> ";
1689 cout
<< "timecode: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< endl
;
1691 for (int i
= 0; i
< 10; i
++) {
1692 _session
->timecode_to_sample( timecode1
, sample1
, true /* use_offset */, false /* use_subframes */ );
1693 _session
->sample_to_timecode( sample1
, timecode2
, true /* use_offset */, false /* use_subframes */ );
1695 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1696 // cout << "sample: " << sample1 << endl;
1697 // cout << "sample: " << sample1 << " -> ";
1698 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1700 // if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1))))
1702 // cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1706 if (timecode2
.hours
!= timecode1
.hours
|| timecode2
.minutes
!= timecode1
.minutes
|| timecode2
.seconds
!= timecode2
.seconds
|| timecode2
.frames
!= timecode1
.frames
) {
1707 cout
<< "ERROR: timecode2 not equal timecode1" << endl
;
1708 cout
<< "timecode: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1709 cout
<< "sample: " << sample1
<< endl
;
1710 cout
<< "sample: " << sample1
<< " -> ";
1711 cout
<< "timecode: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1714 oldsample
= sample1
;
1715 _session
->timecode_increment_hours( timecode1
);
1718 cout
<< "sample_increment: " << sample_increment
<< endl
;
1719 cout
<< "sample: " << sample1
<< " -> ";
1720 cout
<< "timecode: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1729 AudioClock::minsec_frame_from_display () const
1731 if (_session
== 0) {
1735 int hrs
= atoi (label (MS_Hours
)->get_text());
1736 int mins
= atoi (label (MS_Minutes
)->get_text());
1737 int secs
= atoi (label (MS_Seconds
)->get_text());
1738 int millisecs
= atoi (label (MS_Milliseconds
)->get_text());
1740 framecnt_t sr
= _session
->frame_rate();
1742 return (framepos_t
) floor ((hrs
* 60.0f
* 60.0f
* sr
) + (mins
* 60.0f
* sr
) + (secs
* sr
) + (millisecs
* sr
/ 1000.0));
1746 AudioClock::bbt_frame_from_display (framepos_t pos
) const
1748 if (_session
== 0) {
1749 error
<< "AudioClock::current_time() called with BBT mode but without session!" << endmsg
;
1754 any
.type
= AnyTime::BBT
;
1756 any
.bbt
.bars
= atoi (label (Bars
)->get_text());
1757 any
.bbt
.beats
= atoi (label (Beats
)->get_text());
1758 any
.bbt
.ticks
= atoi (label (Ticks
)->get_text());
1763 return _session
->any_duration_to_frames (pos
, any
);
1765 return _session
->convert_to_frames (any
);
1771 AudioClock::bbt_frame_duration_from_display (framepos_t pos
) const
1773 if (_session
== 0) {
1774 error
<< "AudioClock::current_time() called with BBT mode but without session!" << endmsg
;
1778 Timecode::BBT_Time bbt
;
1781 bbt
.bars
= atoi (label (Bars
)->get_text());
1782 bbt
.beats
= atoi (label (Beats
)->get_text());
1783 bbt
.ticks
= atoi (label (Ticks
)->get_text());
1785 return _session
->tempo_map().bbt_duration_at(pos
,bbt
,1);
1789 AudioClock::audio_frame_from_display () const
1791 return (framepos_t
) atoi (label (AudioFrames
)->get_text ());
1795 AudioClock::build_ops_menu ()
1797 using namespace Menu_Helpers
;
1798 ops_menu
= new Menu
;
1799 MenuList
& ops_items
= ops_menu
->items();
1800 ops_menu
->set_name ("ArdourContextMenu");
1802 if (!Profile
->get_sae()) {
1803 ops_items
.push_back (MenuElem (_("Timecode"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode
), Timecode
)));
1805 ops_items
.push_back (MenuElem (_("Bars:Beats"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode
), BBT
)));
1806 ops_items
.push_back (MenuElem (_("Minutes:Seconds"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode
), MinSec
)));
1807 ops_items
.push_back (MenuElem (_("Samples"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode
), Frames
)));
1809 if (editable
&& !is_duration
&& !_follows_playhead
) {
1810 ops_items
.push_back (SeparatorElem());
1811 ops_items
.push_back (MenuElem (_("Set From Playhead"), sigc::mem_fun(*this, &AudioClock::set_from_playhead
)));
1812 ops_items
.push_back (MenuElem (_("Locate to This Time"), sigc::mem_fun(*this, &AudioClock::locate
)));
1817 AudioClock::set_from_playhead ()
1823 set (_session
->transport_frame());
1828 AudioClock::locate ()
1830 if (!_session
|| is_duration
) {
1834 _session
->request_locate (current_time(), _session
->transport_rolling ());
1838 AudioClock::connect_signals ()
1840 scroll_connection
= display
->scroll
.connect (sigc::mem_fun (*this, &AudioClock::scroll
));
1841 button_press_connection
= display
->button_press
.connect (sigc::mem_fun (*this, &AudioClock::button_press
));
1842 button_release_connection
= display
->button_release
.connect (sigc::mem_fun (*this, &AudioClock::button_release
));
1846 AudioClock::set_mode (Mode m
)
1854 display
->clear_cells ();
1856 if (supplemental_left
) {
1857 supplemental_left
->clear_cells ();
1858 supplemental_right
->clear_cells ();
1863 display
->add_cell (_text_cells
[Timecode_Sign
]);
1864 display
->add_cell (_text_cells
[Timecode_Hours
]);
1865 display
->add_cell (_fixed_cells
[Colon1
]);
1866 display
->add_cell (_text_cells
[Timecode_Minutes
]);
1867 display
->add_cell (_fixed_cells
[Colon2
]);
1868 display
->add_cell (_text_cells
[Timecode_Seconds
]);
1869 display
->add_cell (_fixed_cells
[Colon3
]);
1870 display
->add_cell (_text_cells
[Timecode_Frames
]);
1872 if (supplemental_left
) {
1873 supplemental_left
->add_cell (_text_cells
[LowerLeft1
]);
1874 supplemental_left
->add_cell (_text_cells
[LowerLeft2
]);
1875 supplemental_right
->add_cell (_text_cells
[LowerRight1
]);
1876 supplemental_right
->add_cell (_text_cells
[LowerRight2
]);
1878 supplemental_left
->set_width_chars (_text_cells
[LowerLeft1
], 4);
1879 supplemental_left
->set_width_chars (_text_cells
[LowerLeft2
], 8);
1881 supplemental_right
->set_width_chars (_text_cells
[LowerRight1
], 4);
1882 supplemental_right
->set_width_chars (_text_cells
[LowerRight2
], 6.25);
1884 supplemental_left
->set_text (_text_cells
[LowerLeft1
], _("EXT"));
1885 supplemental_right
->set_text (_text_cells
[LowerRight1
], _("FPS"));
1890 display
->add_cell (_text_cells
[Bars
]);
1891 display
->add_cell (_fixed_cells
[Bar1
]);
1892 display
->add_cell (_text_cells
[Beats
]);
1893 display
->add_cell (_fixed_cells
[Bar2
]);
1894 display
->add_cell (_text_cells
[Ticks
]);
1895 if (supplemental_left
) {
1896 supplemental_left
->add_cell (_text_cells
[LowerLeft1
]);
1897 supplemental_left
->add_cell (_text_cells
[LowerLeft2
]);
1898 supplemental_right
->add_cell (_text_cells
[LowerRight1
]);
1899 supplemental_right
->add_cell (_text_cells
[LowerRight2
]);
1901 supplemental_left
->set_width_chars (_text_cells
[LowerLeft1
], 1);
1902 supplemental_left
->set_width_chars (_text_cells
[LowerLeft2
], 5.25);
1904 supplemental_right
->set_width_chars (_text_cells
[LowerRight1
], 2); // why not 1? M is too wide
1905 supplemental_right
->set_width_chars (_text_cells
[LowerRight2
], 5);
1907 supplemental_left
->set_text (_text_cells
[LowerLeft1
], _("T"));
1908 supplemental_right
->set_text (_text_cells
[LowerRight1
], _("M"));
1913 display
->add_cell (_text_cells
[MS_Hours
]);
1914 display
->add_cell (_fixed_cells
[Colon1
]);
1915 display
->add_cell (_text_cells
[MS_Minutes
]);
1916 display
->add_cell (_fixed_cells
[Colon2
]);
1917 display
->add_cell (_text_cells
[MS_Seconds
]);
1918 display
->add_cell (_fixed_cells
[Colon3
]);
1919 display
->add_cell (_text_cells
[MS_Milliseconds
]);
1920 if (supplemental_left
) {
1921 supplemental_left
->add_cell (_text_cells
[LowerLeft1
]);
1922 supplemental_left
->add_cell (_text_cells
[LowerLeft2
]);
1923 supplemental_right
->add_cell (_text_cells
[LowerRight1
]);
1924 supplemental_right
->add_cell (_text_cells
[LowerRight2
]);
1926 /* These are going to remain empty */
1928 supplemental_left
->set_width_chars (_text_cells
[LowerLeft1
], 1);
1929 supplemental_left
->set_width_chars (_text_cells
[LowerLeft2
], 5);
1931 supplemental_right
->set_width_chars (_text_cells
[LowerRight1
], 1);
1932 supplemental_right
->set_width_chars (_text_cells
[LowerRight2
], 1);
1934 supplemental_left
->set_text (_text_cells
[LowerLeft1
], _(" "));
1935 supplemental_right
->set_text (_text_cells
[LowerRight1
], _(" "));
1940 display
->add_cell (_text_cells
[AudioFrames
]);
1941 if (supplemental_left
) {
1942 supplemental_left
->add_cell (_text_cells
[LowerLeft1
]);
1943 supplemental_left
->add_cell (_text_cells
[LowerLeft2
]);
1944 supplemental_right
->add_cell (_text_cells
[LowerRight1
]);
1945 supplemental_right
->add_cell (_text_cells
[LowerRight2
]);
1947 supplemental_left
->set_width_chars (_text_cells
[LowerLeft1
], 3);
1948 supplemental_left
->set_width_chars (_text_cells
[LowerLeft2
], 5);
1950 supplemental_right
->set_width_chars (_text_cells
[LowerRight1
], 5);
1951 supplemental_right
->set_width_chars (_text_cells
[LowerRight2
], 5);
1953 supplemental_left
->set_text (_text_cells
[LowerLeft1
], _("SR"));
1954 supplemental_right
->set_text (_text_cells
[LowerRight1
], _("Pull"));
1959 if (supplemental_left
) {
1960 /* clear information cells */
1961 supplemental_left
->set_text (_text_cells
[LowerLeft2
], _(""));
1962 supplemental_right
->set_text (_text_cells
[LowerRight2
], _(""));
1965 set (last_when
, true);
1967 if (!is_transient
) {
1968 ModeChanged (); /* EMIT SIGNAL (the static one)*/
1971 mode_changed (); /* EMIT SIGNAL (the member one) */
1975 AudioClock::set_bbt_reference (framepos_t pos
)
1977 bbt_reference_time
= pos
;
1981 AudioClock::on_style_changed (const Glib::RefPtr
<Gtk::Style
>& old_style
)
1983 VBox::on_style_changed (old_style
);
1988 AudioClock::set_is_duration (bool yn
)
1990 if (yn
== is_duration
) {
1995 set (last_when
, true, 0, 's');
1999 AudioClock::set_off (bool yn
)
2008 _canonical_time
= current_time ();
2009 _canonical_time_is_displayed
= false;
2011 _canonical_time_is_displayed
= true;
2014 /* force a possible redraw */
2016 set (_canonical_time
, true);