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>
27 #include <gtkmm2ext/utils.h>
29 #include "ardour/ardour.h"
30 #include "ardour/session.h"
31 #include "ardour/tempo.h"
32 #include "ardour/profile.h"
33 #include <sigc++/bind.h>
35 #include "ardour_ui.h"
36 #include "audio_clock.h"
39 #include "gui_thread.h"
42 using namespace ARDOUR
;
47 using Gtkmm2ext::Keyboard
;
52 sigc::signal
<void> AudioClock::ModeChanged
;
53 vector
<AudioClock
*> AudioClock::clocks
;
55 const uint32_t AudioClock::field_length
[(int) AudioClock::AudioFrames
+1] = {
56 2, /* Timecode_Hours */
57 2, /* Timecode_Minutes */
58 2, /* Timecode_Seconds */
59 2, /* Timecode_Frames */
63 3, /* MS_Milliseconds */
70 AudioClock::AudioClock (const string
& clock_name
, bool transient
, const string
& widget_name
,
71 bool allow_edit
, bool follows_playhead
, bool duration
, bool with_info
)
73 is_transient (transient
),
74 is_duration (duration
),
75 editable (allow_edit
),
76 _follows_playhead (follows_playhead
),
86 _canonical_time_is_displayed (true),
89 /* XXX: these are leaked, but I don't suppose it's the end of the world */
91 _eboxes
[Timecode_Hours
] = new EventBox
;
92 _eboxes
[Timecode_Minutes
] = new EventBox
;
93 _eboxes
[Timecode_Seconds
] = new EventBox
;
94 _eboxes
[Timecode_Frames
] = new EventBox
;
95 _eboxes
[MS_Hours
] = new EventBox
;
96 _eboxes
[MS_Minutes
] = new EventBox
;
97 _eboxes
[MS_Seconds
] = new EventBox
;
98 _eboxes
[MS_Milliseconds
] = new EventBox
;
99 _eboxes
[Bars
] = new EventBox
;
100 _eboxes
[Beats
] = new EventBox
;
101 _eboxes
[Ticks
] = new EventBox
;
102 _eboxes
[AudioFrames
] = new EventBox
;
104 _labels
[Timecode_Hours
] = new Label
;
105 _labels
[Timecode_Minutes
] = new Label
;
106 _labels
[Timecode_Seconds
] = new Label
;
107 _labels
[Timecode_Frames
] = new Label
;
108 _labels
[MS_Hours
] = new Label
;
109 _labels
[MS_Minutes
] = new Label
;
110 _labels
[MS_Seconds
] = new Label
;
111 _labels
[MS_Milliseconds
] = new Label
;
112 _labels
[Bars
] = new Label
;
113 _labels
[Beats
] = new Label
;
114 _labels
[Ticks
] = new Label
;
115 _labels
[AudioFrames
] = new Label
;
123 bbt_reference_time
= -1;
126 frames_upper_info_label
= manage (new Label
);
127 frames_lower_info_label
= manage (new Label
);
128 timecode_upper_info_label
= manage (new Label
);
129 timecode_lower_info_label
= manage (new Label
);
130 bbt_upper_info_label
= manage (new Label
);
131 bbt_lower_info_label
= manage (new Label
);
133 frames_upper_info_label
->set_name ("AudioClockFramesUpperInfo");
134 frames_lower_info_label
->set_name ("AudioClockFramesLowerInfo");
135 timecode_upper_info_label
->set_name ("AudioClockTimecodeUpperInfo");
136 timecode_lower_info_label
->set_name ("AudioClockTimecodeLowerInfo");
137 bbt_upper_info_label
->set_name ("AudioClockBBTUpperInfo");
138 bbt_lower_info_label
->set_name ("AudioClockBBTLowerInfo");
140 Gtkmm2ext::set_size_request_to_display_given_text(*timecode_upper_info_label
, "23.98",0,0);
141 Gtkmm2ext::set_size_request_to_display_given_text(*timecode_lower_info_label
, "NDF",0,0);
143 Gtkmm2ext::set_size_request_to_display_given_text(*bbt_upper_info_label
, "88|88",0,0);
144 Gtkmm2ext::set_size_request_to_display_given_text(*bbt_lower_info_label
, "888.88",0,0);
146 frames_info_box
.pack_start (*frames_upper_info_label
, true, true);
147 frames_info_box
.pack_start (*frames_lower_info_label
, true, true);
148 timecode_info_box
.pack_start (*timecode_upper_info_label
, true, true);
149 timecode_info_box
.pack_start (*timecode_lower_info_label
, true, true);
150 bbt_info_box
.pack_start (*bbt_upper_info_label
, true, true);
151 bbt_info_box
.pack_start (*bbt_lower_info_label
, true, true);
154 frames_upper_info_label
= 0;
155 frames_lower_info_label
= 0;
156 timecode_upper_info_label
= 0;
157 timecode_lower_info_label
= 0;
158 bbt_upper_info_label
= 0;
159 bbt_lower_info_label
= 0;
162 frames_packer
.set_homogeneous (false);
163 frames_packer
.set_border_width (2);
164 frames_packer
.pack_start (*_eboxes
[AudioFrames
], false, false);
167 frames_packer
.pack_start (frames_info_box
, false, false, 5);
170 frames_packer_hbox
.pack_start (frames_packer
, true, false);
172 for (std::map
<Field
, EventBox
*>::iterator i
= _eboxes
.begin(); i
!= _eboxes
.end(); ++i
) {
173 i
->second
->add (*_labels
[i
->first
]);
176 timecode_packer
.set_homogeneous (false);
177 timecode_packer
.set_border_width (2);
178 timecode_packer
.pack_start (*_eboxes
[Timecode_Hours
], false, false);
179 timecode_packer
.pack_start (colon1
, false, false);
180 timecode_packer
.pack_start (*_eboxes
[Timecode_Minutes
], false, false);
181 timecode_packer
.pack_start (colon2
, false, false);
182 timecode_packer
.pack_start (*_eboxes
[Timecode_Seconds
], false, false);
183 timecode_packer
.pack_start (colon3
, false, false);
184 timecode_packer
.pack_start (*_eboxes
[Timecode_Frames
], false, false);
187 timecode_packer
.pack_start (timecode_info_box
, false, false, 5);
190 timecode_packer_hbox
.pack_start (timecode_packer
, true, false);
192 bbt_packer
.set_homogeneous (false);
193 bbt_packer
.set_border_width (2);
194 bbt_packer
.pack_start (*_eboxes
[Bars
], false, false);
195 bbt_packer
.pack_start (b1
, false, false);
196 bbt_packer
.pack_start (*_eboxes
[Beats
], false, false);
197 bbt_packer
.pack_start (b2
, false, false);
198 bbt_packer
.pack_start (*_eboxes
[Ticks
], false, false);
201 bbt_packer
.pack_start (bbt_info_box
, false, false, 5);
204 bbt_packer_hbox
.pack_start (bbt_packer
, true, false);
206 minsec_packer
.set_homogeneous (false);
207 minsec_packer
.set_border_width (2);
208 minsec_packer
.pack_start (*_eboxes
[MS_Hours
], false, false);
209 minsec_packer
.pack_start (colon4
, false, false);
210 minsec_packer
.pack_start (*_eboxes
[MS_Minutes
], false, false);
211 minsec_packer
.pack_start (colon5
, false, false);
212 minsec_packer
.pack_start (*_eboxes
[MS_Seconds
], false, false);
213 minsec_packer
.pack_start (period1
, false, false);
214 minsec_packer
.pack_start (*_eboxes
[MS_Milliseconds
], false, false);
216 minsec_packer_hbox
.pack_start (minsec_packer
, true, false);
218 clock_frame
.set_shadow_type (SHADOW_IN
);
219 clock_frame
.set_name ("BaseFrame");
221 clock_frame
.add (clock_base
);
223 set_widget_name (widget_name
);
225 _mode
= BBT
; /* lie to force mode switch */
228 pack_start (clock_frame
, true, true);
230 /* the clock base handles button releases for menu popup regardless of
231 editable status. if the clock is editable, the clock base is where
232 we pass focus to after leaving the last editable "field", which
233 will then shutdown editing till the user starts it up again.
235 it does this because the focus out event on the field disables
236 keyboard event handling, and we don't connect anything up to
237 notice focus in on the clock base. hence, keyboard event handling
241 clock_base
.add_events (Gdk::BUTTON_PRESS_MASK
|Gdk::BUTTON_RELEASE_MASK
|Gdk::SCROLL_MASK
);
242 clock_base
.signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &AudioClock::field_button_release_event
), Timecode_Hours
));
248 set (last_when
, true);
251 clocks
.push_back (this);
256 AudioClock::set_widget_name (string name
)
258 Widget::set_name (name
);
260 clock_base
.set_name (name
);
262 for (std::map
<Field
, EventBox
*>::iterator i
= _eboxes
.begin(); i
!= _eboxes
.end(); ++i
) {
263 i
->second
->set_name (name
);
266 for (std::map
<Field
, Label
*>::iterator i
= _labels
.begin(); i
!= _labels
.end(); ++i
) {
267 i
->second
->set_name (name
);
270 colon1
.set_name (name
);
271 colon2
.set_name (name
);
272 colon3
.set_name (name
);
273 colon4
.set_name (name
);
274 colon5
.set_name (name
);
277 period1
.set_name (name
);
283 AudioClock::setup_events ()
285 clock_base
.set_flags (CAN_FOCUS
);
287 for (std::map
<Field
, EventBox
*>::iterator i
= _eboxes
.begin(); i
!= _eboxes
.end(); ++i
) {
288 i
->second
->add_events (
289 Gdk::BUTTON_PRESS_MASK
|
290 Gdk::BUTTON_RELEASE_MASK
|
291 Gdk::KEY_PRESS_MASK
|
292 Gdk::KEY_RELEASE_MASK
|
293 Gdk::FOCUS_CHANGE_MASK
|
294 Gdk::POINTER_MOTION_MASK
|
297 i
->second
->set_flags (CAN_FOCUS
);
298 i
->second
->signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun (*this, &AudioClock::field_motion_notify_event
), i
->first
));
299 i
->second
->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &AudioClock::field_button_press_event
), i
->first
));
300 i
->second
->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &AudioClock::field_button_release_event
), i
->first
));
301 i
->second
->signal_scroll_event().connect (sigc::bind (sigc::mem_fun (*this, &AudioClock::field_button_scroll_event
), i
->first
));
302 i
->second
->signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &AudioClock::field_key_press_event
), i
->first
));
303 i
->second
->signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &AudioClock::field_key_release_event
), i
->first
));
304 i
->second
->signal_focus_in_event().connect (sigc::bind (sigc::mem_fun (*this, &AudioClock::field_focus_in_event
), i
->first
));
305 i
->second
->signal_focus_out_event().connect (sigc::bind (sigc::mem_fun (*this, &AudioClock::field_focus_out_event
), i
->first
));
308 clock_base
.signal_focus_in_event().connect (sigc::mem_fun (*this, &AudioClock::drop_focus_handler
));
312 AudioClock::drop_focus_handler (GdkEventFocus
*)
314 Keyboard::magic_widget_drop_focus ();
319 AudioClock::on_realize ()
323 /* styles are not available until the widgets are bound to a window */
325 set_size_requests ();
329 AudioClock::set (framepos_t when
, bool force
, framecnt_t offset
, char which
)
331 if ((!force
&& !is_visible()) || _session
== 0) {
335 bool const pdelta
= Config
->get_primary_clock_delta_edit_cursor ();
336 bool const sdelta
= Config
->get_secondary_clock_delta_edit_cursor ();
338 if (offset
&& which
== 'p' && pdelta
) {
339 when
= (when
> offset
) ? when
- offset
: offset
- when
;
340 } else if (offset
&& which
== 's' && sdelta
) {
341 when
= (when
> offset
) ? when
- offset
: offset
- when
;
344 if (when
== last_when
&& !force
) {
348 if (which
== 'p' && pdelta
&& !last_pdelta
) {
349 set_widget_name("TransportClockDisplayDelta");
351 } else if (which
== 'p' && !pdelta
&& last_pdelta
) {
352 set_widget_name("TransportClockDisplay");
354 } else if (which
== 's' && sdelta
&& !last_sdelta
) {
355 set_widget_name("SecondaryClockDisplayDelta");
357 } else if (which
== 's' && !sdelta
&& last_sdelta
) {
358 set_widget_name("SecondaryClockDisplay");
364 set_timecode (when
, force
);
368 set_bbt (when
, force
);
372 set_minsec (when
, force
);
376 set_frames (when
, force
);
385 /* we're setting the time from a frames value, so keep it as the canonical value */
386 _canonical_time
= when
;
387 _canonical_time_is_displayed
= false;
391 AudioClock::session_configuration_changed (std::string p
)
393 if (p
!= "timecode-offset" && p
!= "timecode-offset-negative") {
402 current
= current_duration ();
404 current
= current_time ();
414 AudioClock::set_frames (framepos_t when
, bool /*force*/)
417 snprintf (buf
, sizeof (buf
), "%" PRId64
, when
);
418 _labels
[AudioFrames
]->set_text (buf
);
420 if (frames_upper_info_label
) {
421 framecnt_t rate
= _session
->frame_rate();
423 if (fmod (rate
, 1000.0) == 0.000) {
424 sprintf (buf
, "%" PRId64
"K", rate
/1000);
426 sprintf (buf
, "%.3fK", rate
/1000.0f
);
429 if (frames_upper_info_label
->get_text() != buf
) {
430 frames_upper_info_label
->set_text (buf
);
433 float vid_pullup
= _session
->config
.get_video_pullup();
435 if (vid_pullup
== 0.0) {
436 if (frames_lower_info_label
->get_text () != _("none")) {
437 frames_lower_info_label
->set_text(_("none"));
440 sprintf (buf
, "%-6.4f", vid_pullup
);
441 if (frames_lower_info_label
->get_text() != buf
) {
442 frames_lower_info_label
->set_text (buf
);
449 AudioClock::set_minsec (framepos_t when
, bool force
)
459 hrs
= (int) floor (left
/ (_session
->frame_rate() * 60.0f
* 60.0f
));
460 left
-= (framecnt_t
) floor (hrs
* _session
->frame_rate() * 60.0f
* 60.0f
);
461 mins
= (int) floor (left
/ (_session
->frame_rate() * 60.0f
));
462 left
-= (framecnt_t
) floor (mins
* _session
->frame_rate() * 60.0f
);
463 secs
= (int) floor (left
/ (float) _session
->frame_rate());
464 left
-= (framecnt_t
) floor (secs
* _session
->frame_rate());
465 millisecs
= floor (left
* 1000.0 / (float) _session
->frame_rate());
467 if (force
|| hrs
!= ms_last_hrs
) {
468 sprintf (buf
, "%02d", hrs
);
469 _labels
[MS_Hours
]->set_text (buf
);
473 if (force
|| mins
!= ms_last_mins
) {
474 sprintf (buf
, "%02d", mins
);
475 _labels
[MS_Minutes
]->set_text (buf
);
479 if (force
|| secs
!= ms_last_secs
) {
480 sprintf (buf
, "%02d", secs
);
481 _labels
[MS_Seconds
]->set_text (buf
);
485 if (force
|| millisecs
!= ms_last_millisecs
) {
486 sprintf (buf
, "%03d", millisecs
);
487 _labels
[MS_Milliseconds
]->set_text (buf
);
488 ms_last_millisecs
= millisecs
;
493 AudioClock::set_timecode (framepos_t when
, bool force
)
496 Timecode::Time timecode
;
499 _session
->timecode_duration (when
, timecode
);
501 _session
->timecode_time (when
, timecode
);
504 if (force
|| timecode
.hours
!= last_hrs
|| timecode
.negative
!= last_negative
) {
505 if (timecode
.negative
) {
506 sprintf (buf
, "-%02" PRIu32
, timecode
.hours
);
508 sprintf (buf
, " %02" PRIu32
, timecode
.hours
);
510 _labels
[Timecode_Hours
]->set_text (buf
);
511 last_hrs
= timecode
.hours
;
512 last_negative
= timecode
.negative
;
515 if (force
|| timecode
.minutes
!= last_mins
) {
516 sprintf (buf
, "%02" PRIu32
, timecode
.minutes
);
517 _labels
[Timecode_Minutes
]->set_text (buf
);
518 last_mins
= timecode
.minutes
;
521 if (force
|| timecode
.seconds
!= last_secs
) {
522 sprintf (buf
, "%02" PRIu32
, timecode
.seconds
);
523 _labels
[Timecode_Seconds
]->set_text (buf
);
524 last_secs
= timecode
.seconds
;
527 if (force
|| timecode
.frames
!= last_frames
) {
528 sprintf (buf
, "%02" PRIu32
, timecode
.frames
);
529 _labels
[Timecode_Frames
]->set_text (buf
);
530 last_frames
= timecode
.frames
;
533 if (timecode_upper_info_label
) {
534 double timecode_frames
= _session
->timecode_frames_per_second();
536 if (fmod(timecode_frames
, 1.0) == 0.0) {
537 sprintf (buf
, "%u", int (timecode_frames
));
539 sprintf (buf
, "%.2f", timecode_frames
);
542 if (timecode_upper_info_label
->get_text() != buf
) {
543 timecode_upper_info_label
->set_text (buf
);
546 if ((fabs(timecode_frames
- 29.97) < 0.0001) || timecode_frames
== 30) {
547 if (_session
->timecode_drop_frames()) {
550 sprintf (buf
, "NDF");
553 // there is no drop frame alternative
557 if (timecode_lower_info_label
->get_text() != buf
) {
558 timecode_lower_info_label
->set_text (buf
);
564 AudioClock::set_bbt (framepos_t when
, bool force
)
567 Timecode::BBT_Time bbt
;
569 /* handle a common case */
576 _session
->tempo_map().bbt_time (when
, bbt
);
581 _session
->tempo_map().bbt_time (when
, bbt
);
584 sprintf (buf
, "%03" PRIu32
, bbt
.bars
);
585 if (force
|| _labels
[Bars
]->get_text () != buf
) {
586 _labels
[Bars
]->set_text (buf
);
588 sprintf (buf
, "%02" PRIu32
, bbt
.beats
);
589 if (force
|| _labels
[Beats
]->get_text () != buf
) {
590 _labels
[Beats
]->set_text (buf
);
592 sprintf (buf
, "%04" PRIu32
, bbt
.ticks
);
593 if (force
|| _labels
[Ticks
]->get_text () != buf
) {
594 _labels
[Ticks
]->set_text (buf
);
597 if (bbt_upper_info_label
) {
600 if (bbt_reference_time
< 0) {
603 pos
= bbt_reference_time
;
606 TempoMetric
m (_session
->tempo_map().metric_at (pos
));
608 sprintf (buf
, "%-5.2f", m
.tempo().beats_per_minute());
609 if (bbt_lower_info_label
->get_text() != buf
) {
610 bbt_lower_info_label
->set_text (buf
);
612 sprintf (buf
, "%g|%g", m
.meter().beats_per_bar(), m
.meter().note_divisor());
613 if (bbt_upper_info_label
->get_text() != buf
) {
614 bbt_upper_info_label
->set_text (buf
);
620 AudioClock::set_session (Session
*s
)
622 SessionHandlePtr::set_session (s
);
626 _session
->config
.ParameterChanged
.connect (_session_connections
, invalidator (*this), boost::bind (&AudioClock::session_configuration_changed
, this, _1
), gui_context());
629 XMLNode
* node
= _session
->extra_xml (X_("ClockModes"));
630 AudioClock::Mode amode
;
633 if ((prop
= node
->property (_name
)) != 0) {
634 amode
= AudioClock::Mode (string_2_enum (prop
->value(), amode
));
639 set (last_when
, true);
648 _eboxes
[Timecode_Hours
]->grab_focus ();
652 _eboxes
[Bars
]->grab_focus ();
656 _eboxes
[MS_Hours
]->grab_focus ();
660 _eboxes
[AudioFrames
]->grab_focus ();
670 AudioClock::field_key_press_event (GdkEventKey */
*ev*/
, Field
/*field*/)
672 /* all key activity is handled on key release */
677 AudioClock::field_key_release_event (GdkEventKey
*ev
, Field field
)
679 Label
*label
= _labels
[field
];
682 bool move_on
= false;
684 switch (ev
->keyval
) {
728 if (_mode
== MinSec
&& field
== MS_Seconds
) {
743 clock_base
.grab_focus ();
744 ChangeAborted(); /* EMIT SIGNAL */
753 if (key_entry_state
== 0) {
755 /* initialize with a fresh new string */
757 if (field
!= AudioFrames
) {
758 for (uint32_t xn
= 0; xn
< field_length
[field
] - 1; ++xn
) {
767 string existing
= label
->get_text();
768 if (existing
.length() >= field_length
[field
]) {
769 new_text
= existing
.substr (1, field_length
[field
] - 1);
771 new_text
= existing
.substr (0, field_length
[field
] - 1);
775 new_text
+= new_char
;
776 label
->set_text (new_text
);
777 _canonical_time_is_displayed
= true;
781 if (key_entry_state
== field_length
[field
]) {
787 if (key_entry_state
) {
791 case Timecode_Minutes
:
792 case Timecode_Seconds
:
793 case Timecode_Frames
:
794 // Check Timecode fields for sanity (may also adjust fields)
795 timecode_sanitize_display();
800 // Bars should never be, unless this clock is for a duration
801 if (atoi (_labels
[Bars
]->get_text()) == 0 && !is_duration
) {
802 _labels
[Bars
]->set_text("001");
803 _canonical_time_is_displayed
= true;
805 // beats should never be 0, unless this clock is for a duration
806 if (atoi (_labels
[Beats
]->get_text()) == 0 && !is_duration
) {
807 _labels
[Beats
]->set_text("01");
808 _canonical_time_is_displayed
= true;
815 ValueChanged(); /* EMIT_SIGNAL */
818 /* move on to the next field.
826 _eboxes
[Timecode_Minutes
]->grab_focus ();
828 case Timecode_Minutes
:
829 _eboxes
[Timecode_Seconds
]->grab_focus ();
831 case Timecode_Seconds
:
832 _eboxes
[Timecode_Frames
]->grab_focus ();
834 case Timecode_Frames
:
835 clock_base
.grab_focus ();
840 clock_base
.grab_focus ();
846 _eboxes
[MS_Minutes
]->grab_focus ();
849 _eboxes
[MS_Seconds
]->grab_focus ();
852 _eboxes
[MS_Milliseconds
]->grab_focus ();
854 case MS_Milliseconds
:
855 clock_base
.grab_focus ();
861 _eboxes
[Beats
]->grab_focus ();
864 _eboxes
[Ticks
]->grab_focus ();
867 clock_base
.grab_focus ();
876 //if user hit Enter, lose focus
877 switch (ev
->keyval
) {
880 clock_base
.grab_focus ();
887 AudioClock::field_focus_in_event (GdkEventFocus */
*ev*/
, Field field
)
891 Keyboard::magic_widget_grab_focus ();
893 _eboxes
[field
]->set_flags (HAS_FOCUS
);
894 _eboxes
[field
]->set_state (STATE_ACTIVE
);
900 AudioClock::field_focus_out_event (GdkEventFocus */
*ev*/
, Field field
)
902 _eboxes
[field
]->unset_flags (HAS_FOCUS
);
903 _eboxes
[field
]->set_state (STATE_NORMAL
);
905 Keyboard::magic_widget_drop_focus ();
911 AudioClock::field_button_release_event (GdkEventButton
*ev
, Field field
)
914 gdk_pointer_ungrab (GDK_CURRENT_TIME
);
916 if (ev
->y
> drag_start_y
+1 || ev
->y
< drag_start_y
-1 || Keyboard::modifier_state_equals (ev
->state
, Keyboard::TertiaryModifier
)){
917 // we actually dragged so return without setting editing focus, or we shift clicked
926 ops_menu
->popup (1, ev
->time
);
930 if (Keyboard::is_context_menu_event (ev
)) {
934 ops_menu
->popup (1, ev
->time
);
938 switch (ev
->button
) {
940 _eboxes
[field
]->grab_focus ();
951 AudioClock::field_button_press_event (GdkEventButton
*ev
, Field
/*field*/)
957 framepos_t frames
= 0;
959 switch (ev
->button
) {
961 if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::TertiaryModifier
)) {
963 ValueChanged (); /* EMIT_SIGNAL */
966 /* make absolutely sure that the pointer is grabbed */
967 gdk_pointer_grab(ev
->window
,false ,
968 GdkEventMask( Gdk::POINTER_MOTION_MASK
| Gdk::BUTTON_PRESS_MASK
|Gdk::BUTTON_RELEASE_MASK
),
972 drag_start_y
= ev
->y
;
977 if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::TertiaryModifier
)) {
979 ValueChanged (); /* EMIT_SIGNAL */
984 /* used for context sensitive menu */
997 AudioClock::field_button_scroll_event (GdkEventScroll
*ev
, Field field
)
1003 framepos_t frames
= 0;
1005 switch (ev
->direction
) {
1008 frames
= get_frames (field
);
1010 if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::PrimaryModifier
)) {
1013 set (current_time() + frames
, true);
1014 ValueChanged (); /* EMIT_SIGNAL */
1018 case GDK_SCROLL_DOWN
:
1019 frames
= get_frames (field
);
1021 if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::PrimaryModifier
)) {
1025 if ((double)current_time() - (double)frames
< 0.0) {
1028 set (current_time() - frames
, true);
1031 ValueChanged (); /* EMIT_SIGNAL */
1044 AudioClock::field_motion_notify_event (GdkEventMotion
*ev
, Field field
)
1046 if (_session
== 0 || !dragging
) {
1050 float pixel_frame_scale_factor
= 0.2f
;
1053 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1054 pixel_frame_scale_factor = 0.1f;
1058 if (Keyboard::modifier_state_contains (ev->state,
1059 Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)) {
1061 pixel_frame_scale_factor = 0.025f;
1064 double y_delta
= ev
->y
- drag_y
;
1066 drag_accum
+= y_delta
*pixel_frame_scale_factor
;
1070 if (trunc(drag_accum
) != 0) {
1075 dir
= (drag_accum
< 0 ? 1:-1);
1076 pos
= current_time();
1077 frames
= get_frames (field
,pos
,dir
);
1079 if (frames
!= 0 && frames
* drag_accum
< current_time()) {
1081 set ((framepos_t
) floor (pos
- drag_accum
* frames
), false); // minus because up is negative in computer-land
1089 ValueChanged(); /* EMIT_SIGNAL */
1098 AudioClock::get_frames (Field field
, framepos_t pos
, int dir
)
1100 framecnt_t frames
= 0;
1101 Timecode::BBT_Time bbt
;
1103 case Timecode_Hours
:
1104 frames
= (framecnt_t
) floor (3600.0 * _session
->frame_rate());
1106 case Timecode_Minutes
:
1107 frames
= (framecnt_t
) floor (60.0 * _session
->frame_rate());
1109 case Timecode_Seconds
:
1110 frames
= _session
->frame_rate();
1112 case Timecode_Frames
:
1113 frames
= (framecnt_t
) floor (_session
->frame_rate() / _session
->timecode_frames_per_second());
1121 frames
= (framecnt_t
) floor (3600.0 * _session
->frame_rate());
1124 frames
= (framecnt_t
) floor (60.0 * _session
->frame_rate());
1127 frames
= (framecnt_t
) _session
->frame_rate();
1129 case MS_Milliseconds
:
1130 frames
= (framecnt_t
) floor (_session
->frame_rate() / 1000.0);
1137 frames
= _session
->tempo_map().bbt_duration_at(pos
,bbt
,dir
);
1143 frames
= _session
->tempo_map().bbt_duration_at(pos
,bbt
,dir
);
1149 frames
= _session
->tempo_map().bbt_duration_at(pos
,bbt
,dir
);
1157 AudioClock::current_time (framepos_t pos
) const
1159 if (!_canonical_time_is_displayed
) {
1160 return _canonical_time
;
1167 ret
= timecode_frame_from_display ();
1170 ret
= bbt_frame_from_display (pos
);
1174 ret
= minsec_frame_from_display ();
1178 ret
= audio_frame_from_display ();
1189 AudioClock::current_duration (framepos_t pos
) const
1195 ret
= timecode_frame_from_display ();
1198 ret
= bbt_frame_duration_from_display (pos
);
1202 ret
= minsec_frame_from_display ();
1206 ret
= audio_frame_from_display ();
1217 AudioClock::timecode_sanitize_display()
1219 // Check Timecode fields for sanity, possibly adjusting values
1220 if (atoi (_labels
[Timecode_Minutes
]->get_text()) > 59) {
1221 _labels
[Timecode_Minutes
]->set_text("59");
1222 _canonical_time_is_displayed
= true;
1225 if (atoi (_labels
[Timecode_Seconds
]->get_text()) > 59) {
1226 _labels
[Timecode_Seconds
]->set_text("59");
1227 _canonical_time_is_displayed
= true;
1230 switch ((long)rint(_session
->timecode_frames_per_second())) {
1232 if (atoi (_labels
[Timecode_Frames
]->get_text()) > 23) {
1233 _labels
[Timecode_Frames
]->set_text("23");
1234 _canonical_time_is_displayed
= true;
1238 if (atoi (_labels
[Timecode_Frames
]->get_text()) > 24) {
1239 _labels
[Timecode_Frames
]->set_text("24");
1240 _canonical_time_is_displayed
= true;
1244 if (atoi (_labels
[Timecode_Frames
]->get_text()) > 29) {
1245 _labels
[Timecode_Frames
]->set_text("29");
1246 _canonical_time_is_displayed
= true;
1253 if (_session
->timecode_drop_frames()) {
1254 if ((atoi (_labels
[Timecode_Minutes
]->get_text()) % 10) && (atoi (_labels
[Timecode_Seconds
]->get_text()) == 0) && (atoi (_labels
[Timecode_Frames
]->get_text()) < 2)) {
1255 _labels
[Timecode_Frames
]->set_text("02");
1256 _canonical_time_is_displayed
= true;
1261 /** This is necessary because operator[] isn't const with std::map.
1263 * @return Label widget.
1266 AudioClock::label (Field f
) const
1268 std::map
<Field
, Label
*>::const_iterator i
= _labels
.find (f
);
1269 assert (i
!= _labels
.end ());
1275 AudioClock::timecode_frame_from_display () const
1277 if (_session
== 0) {
1281 Timecode::Time timecode
;
1284 timecode
.hours
= atoi (label (Timecode_Hours
)->get_text());
1285 timecode
.minutes
= atoi (label (Timecode_Minutes
)->get_text());
1286 timecode
.seconds
= atoi (label (Timecode_Seconds
)->get_text());
1287 timecode
.frames
= atoi (label (Timecode_Frames
)->get_text());
1288 timecode
.rate
= _session
->timecode_frames_per_second();
1289 timecode
.drop
= _session
->timecode_drop_frames();
1291 _session
->timecode_to_sample (timecode
, sample
, false /* use_offset */, false /* use_subframes */ );
1295 #define Timecode_SAMPLE_TEST_1
1296 #define Timecode_SAMPLE_TEST_2
1297 #define Timecode_SAMPLE_TEST_3
1298 #define Timecode_SAMPLE_TEST_4
1299 #define Timecode_SAMPLE_TEST_5
1300 #define Timecode_SAMPLE_TEST_6
1301 #define Timecode_SAMPLE_TEST_7
1303 // Testcode for timecode<->sample conversions (P.S.)
1304 Timecode::Time timecode1
;
1306 framepos_t oldsample
= 0;
1307 Timecode::Time timecode2
;
1308 framecnt_t sample_increment
;
1310 sample_increment
= (framecnt_t
)rint(_session
->frame_rate() / _session
->timecode_frames_per_second
);
1312 #ifdef Timecode_SAMPLE_TEST_1
1313 // Test 1: use_offset = false, use_subframes = false
1314 cout
<< "use_offset = false, use_subframes = false" << endl
;
1315 for (int i
= 0; i
< 108003; i
++) {
1316 _session
->timecode_to_sample( timecode1
, sample1
, false /* use_offset */, false /* use_subframes */ );
1317 _session
->sample_to_timecode( sample1
, timecode2
, false /* use_offset */, false /* use_subframes */ );
1319 if ((i
> 0) && ( ((sample1
- oldsample
) != sample_increment
) && ((sample1
- oldsample
) != (sample_increment
+ 1)) && ((sample1
- oldsample
) != (sample_increment
- 1)))) {
1320 cout
<< "ERROR: sample increment not right: " << (sample1
- oldsample
) << " != " << sample_increment
<< endl
;
1321 cout
<< "timecode1: " << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1322 cout
<< "sample: " << sample1
<< endl
;
1323 cout
<< "sample: " << sample1
<< " -> ";
1324 cout
<< "timecode2: " << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1328 if (timecode2
.hours
!= timecode1
.hours
|| timecode2
.minutes
!= timecode1
.minutes
|| timecode2
.seconds
!= timecode2
.seconds
|| timecode2
.frames
!= timecode1
.frames
) {
1329 cout
<< "ERROR: timecode2 not equal timecode1" << endl
;
1330 cout
<< "timecode1: " << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1331 cout
<< "sample: " << sample1
<< endl
;
1332 cout
<< "sample: " << sample1
<< " -> ";
1333 cout
<< "timecode2: " << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1336 oldsample
= sample1
;
1337 _session
->timecode_increment( timecode1
);
1340 cout
<< "sample_increment: " << sample_increment
<< endl
;
1341 cout
<< "sample: " << sample1
<< " -> ";
1342 cout
<< "timecode: " << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1345 #ifdef Timecode_SAMPLE_TEST_2
1346 // Test 2: use_offset = true, use_subframes = false
1347 cout
<< "use_offset = true, use_subframes = false" << endl
;
1349 timecode1
.hours
= 0;
1350 timecode1
.minutes
= 0;
1351 timecode1
.seconds
= 0;
1352 timecode1
.frames
= 0;
1353 timecode1
.subframes
= 0;
1354 sample1
= oldsample
= 0;
1356 _session
->sample_to_timecode( sample1
, timecode1
, true /* use_offset */, false /* use_subframes */ );
1357 cout
<< "Starting at sample: " << sample1
<< " -> ";
1358 cout
<< "timecode: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< endl
;
1360 for (int i
= 0; i
< 108003; i
++) {
1361 _session
->timecode_to_sample( timecode1
, sample1
, true /* use_offset */, false /* use_subframes */ );
1362 _session
->sample_to_timecode( sample1
, timecode2
, true /* use_offset */, false /* use_subframes */ );
1364 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1365 // cout << "sample: " << sample1 << endl;
1366 // cout << "sample: " << sample1 << " -> ";
1367 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1369 if ((i
> 0) && ( ((sample1
- oldsample
) != sample_increment
) && ((sample1
- oldsample
) != (sample_increment
+ 1)) && ((sample1
- oldsample
) != (sample_increment
- 1)))) {
1370 cout
<< "ERROR: sample increment not right: " << (sample1
- oldsample
) << " != " << sample_increment
<< endl
;
1371 cout
<< "timecode1: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1372 cout
<< "sample: " << sample1
<< endl
;
1373 cout
<< "sample: " << sample1
<< " -> ";
1374 cout
<< "timecode2: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1378 if (timecode2
.hours
!= timecode1
.hours
|| timecode2
.minutes
!= timecode1
.minutes
|| timecode2
.seconds
!= timecode2
.seconds
|| timecode2
.frames
!= timecode1
.frames
) {
1379 cout
<< "ERROR: timecode2 not equal timecode1" << endl
;
1380 cout
<< "timecode1: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1381 cout
<< "sample: " << sample1
<< endl
;
1382 cout
<< "sample: " << sample1
<< " -> ";
1383 cout
<< "timecode2: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1386 oldsample
= sample1
;
1387 _session
->timecode_increment( timecode1
);
1390 cout
<< "sample_increment: " << sample_increment
<< endl
;
1391 cout
<< "sample: " << sample1
<< " -> ";
1392 cout
<< "timecode: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1395 #ifdef Timecode_SAMPLE_TEST_3
1396 // Test 3: use_offset = true, use_subframes = false, decrement
1397 cout
<< "use_offset = true, use_subframes = false, decrement" << endl
;
1399 _session
->sample_to_timecode( sample1
, timecode1
, true /* use_offset */, false /* use_subframes */ );
1400 cout
<< "Starting at sample: " << sample1
<< " -> ";
1401 cout
<< "timecode: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< endl
;
1403 for (int i
= 0; i
< 108003; i
++) {
1404 _session
->timecode_to_sample( timecode1
, sample1
, true /* use_offset */, false /* use_subframes */ );
1405 _session
->sample_to_timecode( sample1
, timecode2
, true /* use_offset */, false /* use_subframes */ );
1407 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1408 // cout << "sample: " << sample1 << endl;
1409 // cout << "sample: " << sample1 << " -> ";
1410 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1412 if ((i
> 0) && ( ((oldsample
- sample1
) != sample_increment
) && ((oldsample
- sample1
) != (sample_increment
+ 1)) && ((oldsample
- sample1
) != (sample_increment
- 1)))) {
1413 cout
<< "ERROR: sample increment not right: " << (oldsample
- sample1
) << " != " << sample_increment
<< endl
;
1414 cout
<< "timecode1: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1415 cout
<< "sample: " << sample1
<< endl
;
1416 cout
<< "sample: " << sample1
<< " -> ";
1417 cout
<< "timecode2: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1421 if (timecode2
.hours
!= timecode1
.hours
|| timecode2
.minutes
!= timecode1
.minutes
|| timecode2
.seconds
!= timecode2
.seconds
|| timecode2
.frames
!= timecode1
.frames
) {
1422 cout
<< "ERROR: timecode2 not equal timecode1" << endl
;
1423 cout
<< "timecode1: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1424 cout
<< "sample: " << sample1
<< endl
;
1425 cout
<< "sample: " << sample1
<< " -> ";
1426 cout
<< "timecode2: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1429 oldsample
= sample1
;
1430 _session
->timecode_decrement( timecode1
);
1433 cout
<< "sample_decrement: " << sample_increment
<< endl
;
1434 cout
<< "sample: " << sample1
<< " -> ";
1435 cout
<< "timecode: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1439 #ifdef Timecode_SAMPLE_TEST_4
1440 // Test 4: use_offset = true, use_subframes = true
1441 cout
<< "use_offset = true, use_subframes = true" << endl
;
1443 for (long sub
= 5; sub
< 80; sub
+= 5) {
1444 timecode1
.hours
= 0;
1445 timecode1
.minutes
= 0;
1446 timecode1
.seconds
= 0;
1447 timecode1
.frames
= 0;
1448 timecode1
.subframes
= 0;
1449 sample1
= oldsample
= (sample_increment
* sub
) / 80;
1451 _session
->sample_to_timecode( sample1
, timecode1
, true /* use_offset */, true /* use_subframes */ );
1453 cout
<< "starting at sample: " << sample1
<< " -> ";
1454 cout
<< "timecode: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< endl
;
1456 for (int i
= 0; i
< 108003; i
++) {
1457 _session
->timecode_to_sample( timecode1
, sample1
, true /* use_offset */, true /* use_subframes */ );
1458 _session
->sample_to_timecode( sample1
, timecode2
, true /* use_offset */, true /* use_subframes */ );
1460 if ((i
> 0) && ( ((sample1
- oldsample
) != sample_increment
) && ((sample1
- oldsample
) != (sample_increment
+ 1)) && ((sample1
- oldsample
) != (sample_increment
- 1)))) {
1461 cout
<< "ERROR: sample increment not right: " << (sample1
- oldsample
) << " != " << sample_increment
<< endl
;
1462 cout
<< "timecode1: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1463 cout
<< "sample: " << sample1
<< endl
;
1464 cout
<< "sample: " << sample1
<< " -> ";
1465 cout
<< "timecode2: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1469 if (timecode2
.hours
!= timecode1
.hours
|| timecode2
.minutes
!= timecode1
.minutes
|| timecode2
.seconds
!= timecode2
.seconds
|| timecode2
.frames
!= timecode1
.frames
|| timecode2
.subframes
!= timecode1
.subframes
) {
1470 cout
<< "ERROR: timecode2 not equal timecode1" << endl
;
1471 cout
<< "timecode1: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1472 cout
<< "sample: " << sample1
<< endl
;
1473 cout
<< "sample: " << sample1
<< " -> ";
1474 cout
<< "timecode2: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1477 oldsample
= sample1
;
1478 _session
->timecode_increment( timecode1
);
1481 cout
<< "sample_increment: " << sample_increment
<< endl
;
1482 cout
<< "sample: " << sample1
<< " -> ";
1483 cout
<< "timecode: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1485 for (int i
= 0; i
< 108003; i
++) {
1486 _session
->timecode_to_sample( timecode1
, sample1
, true /* use_offset */, true /* use_subframes */ );
1487 _session
->sample_to_timecode( sample1
, timecode2
, true /* use_offset */, true /* use_subframes */ );
1489 if ((i
> 0) && ( ((oldsample
- sample1
) != sample_increment
) && ((oldsample
- sample1
) != (sample_increment
+ 1)) && ((oldsample
- sample1
) != (sample_increment
- 1)))) {
1490 cout
<< "ERROR: sample increment not right: " << (oldsample
- sample1
) << " != " << sample_increment
<< endl
;
1491 cout
<< "timecode1: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1492 cout
<< "sample: " << sample1
<< endl
;
1493 cout
<< "sample: " << sample1
<< " -> ";
1494 cout
<< "timecode2: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1498 if (timecode2
.hours
!= timecode1
.hours
|| timecode2
.minutes
!= timecode1
.minutes
|| timecode2
.seconds
!= timecode2
.seconds
|| timecode2
.frames
!= timecode1
.frames
|| timecode2
.subframes
!= timecode1
.subframes
) {
1499 cout
<< "ERROR: timecode2 not equal timecode1" << endl
;
1500 cout
<< "timecode1: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1501 cout
<< "sample: " << sample1
<< endl
;
1502 cout
<< "sample: " << sample1
<< " -> ";
1503 cout
<< "timecode2: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1506 oldsample
= sample1
;
1507 _session
->timecode_decrement( timecode1
);
1510 cout
<< "sample_decrement: " << sample_increment
<< endl
;
1511 cout
<< "sample: " << sample1
<< " -> ";
1512 cout
<< "timecode: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1517 #ifdef Timecode_SAMPLE_TEST_5
1518 // Test 5: use_offset = true, use_subframes = false, increment seconds
1519 cout
<< "use_offset = true, use_subframes = false, increment seconds" << endl
;
1521 timecode1
.hours
= 0;
1522 timecode1
.minutes
= 0;
1523 timecode1
.seconds
= 0;
1524 timecode1
.frames
= 0;
1525 timecode1
.subframes
= 0;
1526 sample1
= oldsample
= 0;
1527 sample_increment
= _session
->frame_rate();
1529 _session
->sample_to_timecode( sample1
, timecode1
, true /* use_offset */, false /* use_subframes */ );
1530 cout
<< "Starting at sample: " << sample1
<< " -> ";
1531 cout
<< "timecode: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< endl
;
1533 for (int i
= 0; i
< 3600; i
++) {
1534 _session
->timecode_to_sample( timecode1
, sample1
, true /* use_offset */, false /* use_subframes */ );
1535 _session
->sample_to_timecode( sample1
, timecode2
, true /* use_offset */, false /* use_subframes */ );
1537 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1538 // cout << "sample: " << sample1 << endl;
1539 // cout << "sample: " << sample1 << " -> ";
1540 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1542 // if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1))))
1544 // cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1548 if (timecode2
.hours
!= timecode1
.hours
|| timecode2
.minutes
!= timecode1
.minutes
|| timecode2
.seconds
!= timecode2
.seconds
|| timecode2
.frames
!= timecode1
.frames
) {
1549 cout
<< "ERROR: timecode2 not equal timecode1" << endl
;
1550 cout
<< "timecode: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1551 cout
<< "sample: " << sample1
<< endl
;
1552 cout
<< "sample: " << sample1
<< " -> ";
1553 cout
<< "timecode: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1556 oldsample
= sample1
;
1557 _session
->timecode_increment_seconds( timecode1
);
1560 cout
<< "sample_increment: " << sample_increment
<< endl
;
1561 cout
<< "sample: " << sample1
<< " -> ";
1562 cout
<< "timecode: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1566 #ifdef Timecode_SAMPLE_TEST_6
1567 // Test 6: use_offset = true, use_subframes = false, increment minutes
1568 cout
<< "use_offset = true, use_subframes = false, increment minutes" << endl
;
1570 timecode1
.hours
= 0;
1571 timecode1
.minutes
= 0;
1572 timecode1
.seconds
= 0;
1573 timecode1
.frames
= 0;
1574 timecode1
.subframes
= 0;
1575 sample1
= oldsample
= 0;
1576 sample_increment
= _session
->frame_rate() * 60;
1578 _session
->sample_to_timecode( sample1
, timecode1
, true /* use_offset */, false /* use_subframes */ );
1579 cout
<< "Starting at sample: " << sample1
<< " -> ";
1580 cout
<< "timecode: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< endl
;
1582 for (int i
= 0; i
< 60; i
++) {
1583 _session
->timecode_to_sample( timecode1
, sample1
, true /* use_offset */, false /* use_subframes */ );
1584 _session
->sample_to_timecode( sample1
, timecode2
, true /* use_offset */, false /* use_subframes */ );
1586 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1587 // cout << "sample: " << sample1 << endl;
1588 // cout << "sample: " << sample1 << " -> ";
1589 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1591 // if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1))))
1593 // cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1597 if (timecode2
.hours
!= timecode1
.hours
|| timecode2
.minutes
!= timecode1
.minutes
|| timecode2
.seconds
!= timecode2
.seconds
|| timecode2
.frames
!= timecode1
.frames
) {
1598 cout
<< "ERROR: timecode2 not equal timecode1" << endl
;
1599 cout
<< "timecode: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< " -> ";
1600 cout
<< "sample: " << sample1
<< endl
;
1601 cout
<< "sample: " << sample1
<< " -> ";
1602 cout
<< "timecode: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1605 oldsample
= sample1
;
1606 _session
->timecode_increment_minutes( timecode1
);
1609 cout
<< "sample_increment: " << sample_increment
<< endl
;
1610 cout
<< "sample: " << sample1
<< " -> ";
1611 cout
<< "timecode: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1614 #ifdef Timecode_SAMPLE_TEST_7
1615 // Test 7: use_offset = true, use_subframes = false, increment hours
1616 cout
<< "use_offset = true, use_subframes = false, increment hours" << endl
;
1618 timecode1
.hours
= 0;
1619 timecode1
.minutes
= 0;
1620 timecode1
.seconds
= 0;
1621 timecode1
.frames
= 0;
1622 timecode1
.subframes
= 0;
1623 sample1
= oldsample
= 0;
1624 sample_increment
= _session
->frame_rate() * 60 * 60;
1626 _session
->sample_to_timecode( sample1
, timecode1
, true /* use_offset */, false /* use_subframes */ );
1627 cout
<< "Starting at sample: " << sample1
<< " -> ";
1628 cout
<< "timecode: " << (timecode1
.negative
? "-" : "") << timecode1
.hours
<< ":" << timecode1
.minutes
<< ":" << timecode1
.seconds
<< ":" << timecode1
.frames
<< "::" << timecode1
.subframes
<< endl
;
1630 for (int i
= 0; i
< 10; i
++) {
1631 _session
->timecode_to_sample( timecode1
, sample1
, true /* use_offset */, false /* use_subframes */ );
1632 _session
->sample_to_timecode( sample1
, timecode2
, true /* use_offset */, false /* use_subframes */ );
1634 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1635 // cout << "sample: " << sample1 << endl;
1636 // cout << "sample: " << sample1 << " -> ";
1637 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1639 // if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1))))
1641 // cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1645 if (timecode2
.hours
!= timecode1
.hours
|| timecode2
.minutes
!= timecode1
.minutes
|| timecode2
.seconds
!= timecode2
.seconds
|| timecode2
.frames
!= timecode1
.frames
) {
1646 cout
<< "ERROR: timecode2 not equal timecode1" << endl
;
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
;
1653 oldsample
= sample1
;
1654 _session
->timecode_increment_hours( timecode1
);
1657 cout
<< "sample_increment: " << sample_increment
<< endl
;
1658 cout
<< "sample: " << sample1
<< " -> ";
1659 cout
<< "timecode: " << (timecode2
.negative
? "-" : "") << timecode2
.hours
<< ":" << timecode2
.minutes
<< ":" << timecode2
.seconds
<< ":" << timecode2
.frames
<< "::" << timecode2
.subframes
<< endl
;
1668 AudioClock::minsec_frame_from_display () const
1670 if (_session
== 0) {
1674 int hrs
= atoi (label (MS_Hours
)->get_text());
1675 int mins
= atoi (label (MS_Minutes
)->get_text());
1676 int secs
= atoi (label (MS_Seconds
)->get_text());
1677 int millisecs
= atoi (label (MS_Milliseconds
)->get_text());
1679 framecnt_t sr
= _session
->frame_rate();
1681 return (framepos_t
) floor ((hrs
* 60.0f
* 60.0f
* sr
) + (mins
* 60.0f
* sr
) + (secs
* sr
) + (millisecs
* sr
/ 1000.0));
1685 AudioClock::bbt_frame_from_display (framepos_t pos
) const
1687 if (_session
== 0) {
1688 error
<< "AudioClock::current_time() called with BBT mode but without session!" << endmsg
;
1693 any
.type
= AnyTime::BBT
;
1695 any
.bbt
.bars
= atoi (label (Bars
)->get_text());
1696 any
.bbt
.beats
= atoi (label (Beats
)->get_text());
1697 any
.bbt
.ticks
= atoi (label (Ticks
)->get_text());
1702 return _session
->any_duration_to_frames (pos
, any
);
1704 return _session
->convert_to_frames (any
);
1710 AudioClock::bbt_frame_duration_from_display (framepos_t pos
) const
1712 if (_session
== 0) {
1713 error
<< "AudioClock::current_time() called with BBT mode but without session!" << endmsg
;
1717 Timecode::BBT_Time bbt
;
1720 bbt
.bars
= atoi (label (Bars
)->get_text());
1721 bbt
.beats
= atoi (label (Beats
)->get_text());
1722 bbt
.ticks
= atoi (label (Ticks
)->get_text());
1724 return _session
->tempo_map().bbt_duration_at(pos
,bbt
,1);
1728 AudioClock::audio_frame_from_display () const
1730 return (framepos_t
) atoi (label (AudioFrames
)->get_text ());
1734 AudioClock::build_ops_menu ()
1736 using namespace Menu_Helpers
;
1737 ops_menu
= new Menu
;
1738 MenuList
& ops_items
= ops_menu
->items();
1739 ops_menu
->set_name ("ArdourContextMenu");
1741 if (!Profile
->get_sae()) {
1742 ops_items
.push_back (MenuElem (_("Timecode"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode
), Timecode
)));
1744 ops_items
.push_back (MenuElem (_("Bars:Beats"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode
), BBT
)));
1745 ops_items
.push_back (MenuElem (_("Minutes:Seconds"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode
), MinSec
)));
1746 ops_items
.push_back (MenuElem (_("Samples"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode
), Frames
)));
1747 ops_items
.push_back (MenuElem (_("Off"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode
), Off
)));
1749 if (editable
&& !is_duration
&& !_follows_playhead
) {
1750 ops_items
.push_back (SeparatorElem());
1751 ops_items
.push_back (MenuElem (_("Set From Playhead"), sigc::mem_fun(*this, &AudioClock::set_from_playhead
)));
1752 ops_items
.push_back (MenuElem (_("Locate to This Time"), sigc::mem_fun(*this, &AudioClock::locate
)));
1757 AudioClock::set_from_playhead ()
1763 set (_session
->transport_frame());
1768 AudioClock::locate ()
1770 if (!_session
|| is_duration
) {
1774 _session
->request_locate (current_time(), _session
->transport_rolling ());
1778 AudioClock::set_mode (Mode m
)
1780 /* slightly tricky: this is called from within the ARDOUR_UI
1781 constructor by some of its clock members. at that time
1782 the instance pointer is unset, so we have to be careful.
1783 the main idea is to drop keyboard focus in case we had
1784 started editing the clock and then we switch clock mode.
1787 clock_base
.grab_focus ();
1793 clock_base
.remove ();
1799 clock_base
.add (timecode_packer_hbox
);
1803 clock_base
.add (bbt_packer_hbox
);
1807 clock_base
.add (minsec_packer_hbox
);
1811 clock_base
.add (frames_packer_hbox
);
1815 clock_base
.add (off_hbox
);
1819 set_size_requests ();
1821 set (last_when
, true);
1822 clock_base
.show_all ();
1823 key_entry_state
= 0;
1825 if (!is_transient
) {
1826 ModeChanged (); /* EMIT SIGNAL (the static one)*/
1829 mode_changed (); /* EMIT SIGNAL (the member one) */
1833 AudioClock::set_size_requests ()
1835 /* note that in some fonts, "88" is narrower than "00" */
1839 Gtkmm2ext::set_size_request_to_display_given_text (*_labels
[Timecode_Hours
], "-88", 5, 5);
1840 Gtkmm2ext::set_size_request_to_display_given_text (*_labels
[Timecode_Minutes
], "88", 5, 5);
1841 Gtkmm2ext::set_size_request_to_display_given_text (*_labels
[Timecode_Seconds
], "88", 5, 5);
1842 Gtkmm2ext::set_size_request_to_display_given_text (*_labels
[Timecode_Frames
], "88", 5, 5);
1846 Gtkmm2ext::set_size_request_to_display_given_text (*_labels
[Bars
], "-888", 5, 5);
1847 Gtkmm2ext::set_size_request_to_display_given_text (*_labels
[Beats
], "88", 5, 5);
1848 Gtkmm2ext::set_size_request_to_display_given_text (*_labels
[Ticks
], "8888", 5, 5);
1852 Gtkmm2ext::set_size_request_to_display_given_text (*_labels
[MS_Hours
], "88", 5, 5);
1853 Gtkmm2ext::set_size_request_to_display_given_text (*_labels
[MS_Minutes
], "88", 5, 5);
1854 Gtkmm2ext::set_size_request_to_display_given_text (*_labels
[MS_Seconds
], "88", 5, 5);
1855 Gtkmm2ext::set_size_request_to_display_given_text (*_labels
[MS_Milliseconds
], "888", 5, 5);
1859 Gtkmm2ext::set_size_request_to_display_given_text (*_labels
[AudioFrames
], "8888888888", 5, 5);
1863 Gtkmm2ext::set_size_request_to_display_given_text (off_hbox
, "00000", 5, 5);
1870 AudioClock::set_bbt_reference (framepos_t pos
)
1872 bbt_reference_time
= pos
;
1876 AudioClock::on_style_changed (const Glib::RefPtr
<Gtk::Style
>& old_style
)
1878 HBox::on_style_changed (old_style
);
1880 /* propagate style changes to all component widgets that should inherit the main one */
1882 Glib::RefPtr
<RcStyle
> rcstyle
= get_modifier_style();
1884 clock_base
.modify_style (rcstyle
);
1886 for (std::map
<Field
, Label
*>::iterator i
= _labels
.begin(); i
!= _labels
.end(); ++i
) {
1887 i
->second
->modify_style (rcstyle
);
1890 for (std::map
<Field
, EventBox
*>::iterator i
= _eboxes
.begin(); i
!= _eboxes
.end(); ++i
) {
1891 i
->second
->modify_style (rcstyle
);
1894 colon1
.modify_style (rcstyle
);
1895 colon2
.modify_style (rcstyle
);
1896 colon3
.modify_style (rcstyle
);
1897 colon4
.modify_style (rcstyle
);
1898 colon5
.modify_style (rcstyle
);
1899 b1
.modify_style (rcstyle
);
1900 b2
.modify_style (rcstyle
);
1901 period1
.modify_style (rcstyle
);
1903 set_size_requests ();
1907 AudioClock::set_is_duration (bool yn
)
1909 if (yn
== is_duration
) {
1914 set (last_when
, true, 0, 's');