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"
30 #include "gtkmm2ext/rgb_macros.h"
32 #include "ardour/ardour.h"
33 #include "ardour/session.h"
34 #include "ardour/tempo.h"
35 #include "ardour/profile.h"
36 #include <sigc++/bind.h>
38 #include "ardour_ui.h"
39 #include "audio_clock.h"
42 #include "gui_thread.h"
45 using namespace ARDOUR;
50 using Gtkmm2ext::Keyboard;
52 sigc::signal<void> AudioClock::ModeChanged;
53 vector<AudioClock*> AudioClock::clocks;
54 const double AudioClock::info_font_scale_factor = 0.6;
55 const double AudioClock::separator_height = 2.0;
57 AudioClock::AudioClock (const string& clock_name, bool transient, const string& widget_name,
58 bool allow_edit, bool follows_playhead, bool duration, bool with_info)
60 , is_transient (transient)
61 , is_duration (duration)
62 , editable (allow_edit)
63 , _follows_playhead (follows_playhead)
70 , mode_based_info_ratio (1.0)
72 , bbt_reference_time (-1)
77 , drag_field (Field (0))
78 , _canonical_time_is_displayed (true)
82 set_flags (CAN_FOCUS);
84 _layout = Pango::Layout::create (get_pango_context());
85 _layout->set_attributes (normal_attributes);
88 _left_layout = Pango::Layout::create (get_pango_context());
89 _right_layout = Pango::Layout::create (get_pango_context());
92 set_widget_name (widget_name);
94 _mode = BBT; /* lie to force mode switch */
96 set (last_when, true);
99 clocks.push_back (this);
103 AudioClock::~AudioClock ()
105 delete background_attr;
106 delete foreground_attr;
111 AudioClock::set_widget_name (const string& str)
116 set_name (str + " clock");
122 AudioClock::on_realize ()
124 CairoWidget::on_realize ();
130 AudioClock::set_font ()
132 Glib::RefPtr<Gtk::Style> style = get_style ();
133 Pango::FontDescription font;
134 Pango::AttrFontDesc* font_attr;
136 if (!is_realized()) {
137 font = get_font_for_style (get_name());
139 font = style->get_font();
142 font_attr = new Pango::AttrFontDesc (Pango::Attribute::create_attr_font_desc (font));
144 normal_attributes.change (*font_attr);
145 editing_attributes.change (*font_attr);
147 /* now a smaller version of the same font */
150 font.set_size ((int) lrint (font.get_size() * info_font_scale_factor));
151 font.set_weight (Pango::WEIGHT_NORMAL);
152 font_attr = new Pango::AttrFontDesc (Pango::Attribute::create_attr_font_desc (font));
154 info_attributes.change (*font_attr);
160 AudioClock::set_active_state (Gtkmm2ext::ActiveState s)
162 CairoWidget::set_active_state (s);
167 AudioClock::set_colors ()
173 uint32_t editing_color;
175 if (active_state()) {
176 bg_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1 active: background", get_name()));
177 text_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1 active: text", get_name()));
178 editing_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1 active: edited text", get_name()));
180 bg_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1: background", get_name()));
181 text_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1: text", get_name()));
182 editing_color = ARDOUR_UI::config()->color_by_name (string_compose ("%1: edited text", get_name()));
185 UINT_TO_RGBA (bg_color, &r, &g, &b, &a);
186 r = lrint ((r/256.0) * 65535.0);
187 g = lrint ((g/256.0) * 65535.0);
188 b = lrint ((b/256.0) * 65535.0);
189 background_attr = new Pango::AttrColor (Pango::Attribute::create_attr_background (r, g, b));
191 /* store for bg in ::render() */
197 UINT_TO_RGBA (text_color, &r, &g, &b, &a);
198 r = lrint ((r/256.0) * 65535.0);
199 g = lrint ((g/256.0) * 65535.0);
200 b = lrint ((b/256.0) * 65535.0);
201 foreground_attr = new Pango::AttrColor (Pango::Attribute::create_attr_foreground (r, g, b));
203 UINT_TO_RGBA (editing_color, &r, &g, &b, &a);
204 r = lrint ((r/256.0) * 65535.0);
205 g = lrint ((g/256.0) * 65535.0);
206 b = lrint ((b/256.0) * 65535.0);
207 editing_attr = new Pango::AttrColor (Pango::Attribute::create_attr_foreground (r, g, b));
209 normal_attributes.change (*background_attr);
210 normal_attributes.change (*foreground_attr);
212 info_attributes.change (*background_attr);
213 info_attributes.change (*foreground_attr);
215 editing_attributes.change (*background_attr);
216 editing_attributes.change (*foreground_attr);
217 editing_attributes.change (*editing_attr);
220 _layout->set_attributes (normal_attributes);
222 _layout->set_attributes (editing_attributes);
226 _left_layout->set_attributes (info_attributes);
227 _right_layout->set_attributes (info_attributes);
234 AudioClock::render (cairo_t* cr)
237 /* paint entire area the color of the parent window bg
239 XXX try to optimize this so that we just paint the corners and
240 other areas that may be exposed by rounded corners.
243 Gdk::Color bg (get_parent_bg());
244 cairo_rectangle (cr, 0, 0, _width, _height);
245 cairo_stroke_preserve (cr);
246 cairo_set_source_rgb (cr, bg.get_red_p(), bg.get_green_p(), bg.get_blue_p());
250 /* main layout: rounded rect, plus the text */
252 cairo_set_source_rgba (cr, bg_r, bg_g, bg_b, bg_a);
253 Gtkmm2ext::rounded_rectangle (cr, 0, 0, _width, upper_height, 9);
255 cairo_move_to (cr, 6, (upper_height - layout_height) / 2.0);
256 pango_cairo_show_layout (cr, _layout->gobj());
260 double h = _height - upper_height - separator_height;
262 if (mode_based_info_ratio != 1.0) {
264 double left_rect_width = round (((_width - separator_height) * mode_based_info_ratio) + 0.5);
266 cairo_set_source_rgba (cr, bg_r, bg_g, bg_b, bg_a);
267 Gtkmm2ext::rounded_rectangle (cr, 0, upper_height + separator_height, left_rect_width, h, 9);
269 cairo_move_to (cr, 6, upper_height + separator_height + ((h - info_height)/2.0));
270 pango_cairo_show_layout (cr, _left_layout->gobj());
272 Gtkmm2ext::rounded_rectangle (cr, left_rect_width + separator_height, upper_height + separator_height,
273 _width - separator_height - left_rect_width, h, 9);
275 cairo_move_to (cr, 6 + left_rect_width + separator_height, upper_height + separator_height + ((h - info_height)/2.0));
276 pango_cairo_show_layout (cr, _right_layout->gobj());
279 /* no info to display, or just one */
281 cairo_set_source_rgba (cr, bg_r, bg_g, bg_b, bg_a);
282 Gtkmm2ext::rounded_rectangle (cr, 0, upper_height + separator_height, _width, h, 9);
288 AudioClock::on_size_allocate (Gtk::Allocation& alloc)
290 CairoWidget::on_size_allocate (alloc);
293 upper_height = (_height/2.0) - 1.0;
295 upper_height = _height;
300 AudioClock::on_size_request (Gtk::Requisition* req)
302 Glib::RefPtr<Pango::Layout> tmp;
303 Glib::RefPtr<Gtk::Style> style = get_style ();
304 Pango::FontDescription font;
306 tmp = Pango::Layout::create (get_pango_context());
308 if (!is_realized()) {
309 font = get_font_for_style (get_name());
311 font = style->get_font();
314 tmp->set_font_description (font);
316 /* this string is the longest thing we will ever display,
317 and also includes the BBT "|" that may descends below
318 the baseline a bit, and a comma for the minsecs mode
319 where we printf a fractional value (XXX or should)
322 tmp->set_text (" 88|88:88:88,88");
324 tmp->get_pixel_size (req->width, req->height);
326 layout_height = req->height;
327 layout_width = req->width;
329 /* now tackle height, for which we need to know the height of the lower
337 font.set_size ((int) lrint (font.get_size() * info_font_scale_factor));
338 font.set_weight (Pango::WEIGHT_NORMAL);
339 tmp->set_font_description (font);
341 /* we only care about height, so put as much stuff in here
342 as possible that might change the height.
344 tmp->set_text ("qyhH|"); /* one ascender, one descender */
346 tmp->get_pixel_size (w, info_height);
350 req->height += info_height;
351 req->height += separator_height;
356 AudioClock::show_edit_status (int length)
358 editing_attr->set_start_index (edit_string.length() - length);
359 editing_attr->set_end_index (edit_string.length());
361 editing_attributes.change (*background_attr);
362 editing_attributes.change (*foreground_attr);
363 editing_attributes.change (*editing_attr);
365 _layout->set_attributes (editing_attributes);
369 AudioClock::start_edit ()
371 edit_string = _layout->get_text ();
372 pre_edit_string = edit_string;
373 input_string.clear ();
376 show_edit_status (1);
378 Keyboard::magic_widget_grab_focus ();
383 AudioClock::end_edit (bool modify)
391 ok = timecode_validate_edit (edit_string);
395 ok = bbt_validate_edit (edit_string);
406 edit_string = pre_edit_string;
407 input_string.clear ();
408 _layout->set_text (edit_string);
411 _layout->set_attributes (normal_attributes);
412 ValueChanged(); /* EMIT_SIGNAL */
417 _layout->set_text (pre_edit_string);
424 /* move focus back to the default widget in the top level window */
426 Keyboard::magic_widget_drop_focus ();
428 Widget* top = get_toplevel();
430 if (top->is_toplevel ()) {
431 Window* win = dynamic_cast<Window*> (top);
438 AudioClock::session_configuration_changed (std::string p)
440 if (p != "timecode-offset" && p != "timecode-offset-negative") {
449 current = current_duration ();
451 current = current_time ();
461 AudioClock::set (framepos_t when, bool force, framecnt_t offset, char which)
463 if ((!force && !is_visible()) || _session == 0) {
467 bool const pdelta = Config->get_primary_clock_delta_edit_cursor ();
468 bool const sdelta = Config->get_secondary_clock_delta_edit_cursor ();
470 if (offset && which == 'p' && pdelta) {
471 when = (when > offset) ? when - offset : offset - when;
472 } else if (offset && which == 's' && sdelta) {
473 when = (when > offset) ? when - offset : offset - when;
476 if (when == last_when && !force) {
480 if (which == 'p' && pdelta && !last_pdelta) {
481 set_name("TransportClockDisplayDelta");
483 } else if (which == 'p' && !pdelta && last_pdelta) {
484 set_name("TransportClockDisplay");
486 } else if (which == 's' && sdelta && !last_sdelta) {
487 set_name("SecondaryClockDisplayDelta");
489 } else if (which == 's' && !sdelta && last_sdelta) {
490 set_name("SecondaryClockDisplay");
498 set_timecode (when, force);
502 set_bbt (when, force);
506 set_minsec (when, force);
510 set_frames (when, force);
515 if (when != last_when || force) {
521 /* we're setting the time from a frames value, so keep it as the canonical value */
522 _canonical_time = when;
523 _canonical_time_is_displayed = false;
527 AudioClock::set_frames (framepos_t when, bool /*force*/)
532 /* XXX with cairo, we can do better, surely? */
534 _layout->set_text ("-----------");
537 _left_layout->set_text ("");
538 _right_layout->set_text ("");
544 snprintf (buf, sizeof (buf), "%10" PRId64, when);
545 _layout->set_text (buf);
548 framecnt_t rate = _session->frame_rate();
550 if (fmod (rate, 1000.0) == 0.000) {
551 sprintf (buf, "%" PRId64 "K", rate/1000);
553 sprintf (buf, "%" PRId64, rate);
556 _left_layout->set_text (buf);
558 float vid_pullup = _session->config.get_video_pullup();
560 if (vid_pullup == 0.0) {
561 _right_layout->set_text (_("none"));
563 sprintf (buf, "%-6.4f", vid_pullup);
564 _right_layout->set_text (buf);
570 AudioClock::set_minsec (framepos_t when, bool force)
580 _layout->set_text ("--:--:--");
583 _left_layout->set_text ("");
584 _right_layout->set_text ("");
591 hrs = (int) floor (left / (_session->frame_rate() * 60.0f * 60.0f));
592 left -= (framecnt_t) floor (hrs * _session->frame_rate() * 60.0f * 60.0f);
593 mins = (int) floor (left / (_session->frame_rate() * 60.0f));
594 left -= (framecnt_t) floor (mins * _session->frame_rate() * 60.0f);
595 secs = (int) floor (left / (float) _session->frame_rate());
596 left -= (framecnt_t) floor (secs * _session->frame_rate());
597 millisecs = floor (left * 1000.0 / (float) _session->frame_rate());
599 snprintf (buf, sizeof (buf), "%02" PRIu32 ":%02" PRIu32 ":%02" PRIu32 ".%03" PRIu32, hrs, mins, secs, millisecs);
600 _layout->set_text (buf);
604 AudioClock::set_timecode (framepos_t when, bool force)
610 _layout->set_text ("--:--:--:--");
612 _left_layout->set_text ("");
613 _right_layout->set_text ("");
620 _session->timecode_duration (when, TC);
622 _session->timecode_time (when, TC);
626 snprintf (buf, sizeof (buf), "-%02" PRIu32 ":%02" PRIu32 ":%02" PRIu32 ":%02" PRIu32, TC.hours, TC.minutes, TC.seconds, TC.frames);
628 snprintf (buf, sizeof (buf), " %02" PRIu32 ":%02" PRIu32 ":%02" PRIu32 ":%02" PRIu32, TC.hours, TC.minutes, TC.seconds, TC.frames);
631 _layout->set_text (buf);
634 double timecode_frames = _session->timecode_frames_per_second();
636 if (fmod(timecode_frames, 1.0) == 0.0) {
637 sprintf (buf, "FPS %u %s", int (timecode_frames), (_session->timecode_drop_frames() ? "D" : ""));
639 sprintf (buf, "%.2f %s", timecode_frames, (_session->timecode_drop_frames() ? "D" : ""));
642 _right_layout->set_text (buf);
647 AudioClock::set_bbt (framepos_t when, bool force)
650 Timecode::BBT_Time BBT;
653 _layout->set_text ("--|--|--");
655 _left_layout->set_text ("");
656 _right_layout->set_text ("");
661 /* handle a common case */
668 _session->tempo_map().bbt_time (when, BBT);
673 _session->tempo_map().bbt_time (when, BBT);
676 snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%04" PRIu32, BBT.bars, BBT.beats, BBT.ticks);
677 _layout->set_text (buf);
682 if (bbt_reference_time < 0) {
685 pos = bbt_reference_time;
688 TempoMetric m (_session->tempo_map().metric_at (pos));
690 sprintf (buf, "%-5.2f", m.tempo().beats_per_minute());
691 _left_layout->set_text (buf);
693 sprintf (buf, "%g|%g", m.meter().beats_per_bar(), m.meter().note_divisor());
694 _right_layout->set_text (buf);
699 AudioClock::set_session (Session *s)
701 SessionHandlePtr::set_session (s);
705 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&AudioClock::session_configuration_changed, this, _1), gui_context());
707 const XMLProperty* prop;
708 XMLNode* node = _session->extra_xml (X_("ClockModes"));
709 AudioClock::Mode amode;
712 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
713 if ((prop = (*i)->property (X_("name"))) && prop->value() == _name) {
715 if ((prop = (*i)->property (X_("mode"))) != 0) {
716 amode = AudioClock::Mode (string_2_enum (prop->value(), amode));
719 if ((prop = (*i)->property (X_("on"))) != 0) {
720 set_off (!string_is_affirmative (prop->value()));
727 set (last_when, true);
732 AudioClock::on_key_press_event (GdkEventKey* ev)
738 /* return true for keys that we MIGHT use
741 switch (ev->keyval) {
776 AudioClock::on_key_release_event (GdkEventKey *ev)
785 switch (ev->keyval) {
836 ChangeAborted(); /* EMIT SIGNAL */
843 if (input_string.length() >= insert_max) {
844 /* eat the key event, but do no nothing with it */
848 input_string.insert (input_string.begin(), new_char);
850 string::reverse_iterator ri;
851 vector<int> insert_at;
852 int highlight_length;
854 /* merge with pre-edit-string into edit string */
858 edit_string = input_string;
859 highlight_length = edit_string.length();
863 edit_string = pre_edit_string;
865 /* backup through the original string, till we have
866 * enough digits locations to put all the digits from
870 for (ri = edit_string.rbegin(); ri != edit_string.rend(); ++ri) {
872 insert_at.push_back (edit_string.length() - (ri - edit_string.rbegin()) - 1);
873 if (insert_at.size() == input_string.length()) {
879 if (insert_at.size() != input_string.length()) {
880 error << "something went wrong " << endmsg;
882 for (int i = input_string.length() - 1; i >= 0; --i) {
883 edit_string[insert_at[i]] = input_string[i];
886 highlight_length = edit_string.length() - insert_at.back();
892 if (edit_string != _layout->get_text()) {
893 show_edit_status (highlight_length);
894 _layout->set_text (edit_string);
902 AudioClock::index_to_field (int index) const
907 return Timecode_Hours;
908 } else if (index < 7) {
909 return Timecode_Minutes;
910 } else if (index < 10) {
911 return Timecode_Seconds;
912 } else if (index < 13) {
913 return Timecode_Frames;
921 } else if (index < 7) {
923 } else if (index < 12) {
932 return Timecode_Hours;
933 } else if (index < 6) {
935 } else if (index < 9) {
937 } else if (index < 12) {
938 return MS_Milliseconds;
951 AudioClock::on_button_press_event (GdkEventButton *ev)
953 switch (ev->button) {
957 /* make absolutely sure that the pointer is grabbed */
958 gdk_pointer_grab(ev->window,false ,
959 GdkEventMask( Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK |Gdk::BUTTON_RELEASE_MASK),
962 drag_start_y = ev->y;
968 if (_layout->xy_to_index (ev->x * PANGO_SCALE, ev->y * PANGO_SCALE, index, trailing)) {
969 drag_field = index_to_field (index);
971 drag_field = Field (0);
985 AudioClock::on_button_release_event (GdkEventButton *ev)
989 gdk_pointer_ungrab (GDK_CURRENT_TIME);
991 if (ev->y > drag_start_y+1 || ev->y < drag_start_y-1 || Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)){
992 // we actually dragged so return without
993 // setting editing focus, or we shift clicked
996 if (ev->button == 1) {
1004 if (Keyboard::is_context_menu_event (ev)) {
1005 if (ops_menu == 0) {
1008 ops_menu->popup (1, ev->time);
1016 AudioClock::on_scroll_event (GdkEventScroll *ev)
1021 if (_session == 0 || !editable) {
1025 if (!_layout->xy_to_index (ev->x * PANGO_SCALE, ev->y * PANGO_SCALE, index, trailing)) {
1026 /* not in the main layout */
1030 Field f = index_to_field (index);
1031 framepos_t frames = 0;
1033 switch (ev->direction) {
1036 frames = get_frame_step (f);
1038 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1041 set (current_time() + frames, true);
1042 ValueChanged (); /* EMIT_SIGNAL */
1046 case GDK_SCROLL_DOWN:
1047 frames = get_frame_step (f);
1049 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1053 if ((double)current_time() - (double)frames < 0.0) {
1056 set (current_time() - frames, true);
1059 ValueChanged (); /* EMIT_SIGNAL */
1072 AudioClock::on_motion_notify_event (GdkEventMotion *ev)
1074 if (_session == 0 || !dragging) {
1078 float pixel_frame_scale_factor = 0.2f;
1080 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1081 pixel_frame_scale_factor = 0.1f;
1085 if (Keyboard::modifier_state_contains (ev->state,
1086 Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)) {
1088 pixel_frame_scale_factor = 0.025f;
1091 double y_delta = ev->y - drag_y;
1093 drag_accum += y_delta*pixel_frame_scale_factor;
1097 if (trunc (drag_accum) != 0) {
1102 dir = (drag_accum < 0 ? 1:-1);
1103 pos = current_time();
1104 frames = get_frame_step (drag_field,pos,dir);
1106 if (frames != 0 && frames * drag_accum < current_time()) {
1107 set ((framepos_t) floor (pos - drag_accum * frames), false); // minus because up is negative in GTK
1113 ValueChanged(); /* EMIT_SIGNAL */
1120 AudioClock::get_frame_step (Field field, framepos_t pos, int dir)
1123 Timecode::BBT_Time BBT;
1125 case Timecode_Hours:
1126 f = (framecnt_t) floor (3600.0 * _session->frame_rate());
1128 case Timecode_Minutes:
1129 f = (framecnt_t) floor (60.0 * _session->frame_rate());
1131 case Timecode_Seconds:
1132 f = _session->frame_rate();
1134 case Timecode_Frames:
1135 f = (framecnt_t) floor (_session->frame_rate() / _session->timecode_frames_per_second());
1143 f = (framecnt_t) floor (3600.0 * _session->frame_rate());
1146 f = (framecnt_t) floor (60.0 * _session->frame_rate());
1149 f = (framecnt_t) _session->frame_rate();
1151 case MS_Milliseconds:
1152 f = (framecnt_t) floor (_session->frame_rate() / 1000.0);
1159 f = _session->tempo_map().bbt_duration_at (pos,BBT,dir);
1165 f = _session->tempo_map().bbt_duration_at(pos,BBT,dir);
1171 f = _session->tempo_map().bbt_duration_at(pos,BBT,dir);
1174 error << string_compose (_("programming error: %1"), "attempt to get frames from non-text field!") << endmsg;
1183 AudioClock::current_time (framepos_t pos) const
1185 // if (!_canonical_time_is_displayed) {
1186 // return _canonical_time;
1193 ret = timecode_frame_from_display ();
1196 ret = bbt_frame_from_display (pos);
1200 ret = minsec_frame_from_display ();
1204 ret = audio_frame_from_display ();
1212 AudioClock::current_duration (framepos_t pos) const
1218 ret = timecode_frame_from_display ();
1221 ret = bbt_frame_duration_from_display (pos);
1225 ret = minsec_frame_from_display ();
1229 ret = audio_frame_from_display ();
1237 AudioClock::bbt_validate_edit (const string& str)
1241 sscanf (str.c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32, &any.bbt.bars, &any.bbt.beats, &any.bbt.ticks);
1243 if (!is_duration && any.bbt.bars == 0) {
1247 if (!is_duration && any.bbt.beats == 0) {
1255 AudioClock::timecode_validate_edit (const string& str)
1259 if (sscanf (_layout->get_text().c_str(), "%" PRId32 ":%" PRId32 ":%" PRId32 ":%" PRId32,
1260 &TC.hours, &TC.minutes, &TC.seconds, &TC.frames) != 4) {
1264 if (TC.minutes > 59 || TC.seconds > 59) {
1268 if (TC.frames > (long)rint(_session->timecode_frames_per_second()) - 1) {
1272 if (_session->timecode_drop_frames()) {
1273 if (TC.minutes % 10 && TC.seconds == 0 && TC.frames < 2) {
1282 AudioClock::timecode_frame_from_display () const
1284 if (_session == 0) {
1291 sscanf (_layout->get_text().c_str(), "%d:%d:%d:%d", &TC.hours, &TC.minutes, &TC.seconds, &TC.frames);
1293 TC.rate = _session->timecode_frames_per_second();
1294 TC.drop= _session->timecode_drop_frames();
1296 _session->timecode_to_sample (TC, sample, false /* use_offset */, false /* use_subframes */ );
1298 // timecode_tester ();
1304 AudioClock::minsec_frame_from_display () const
1306 if (_session == 0) {
1310 int hrs, mins, secs, millisecs;
1311 framecnt_t sr = _session->frame_rate();
1313 sscanf (_layout->get_text().c_str(), "%d:%d:%d:%d", &hrs, &mins, &secs, &millisecs);
1314 return (framepos_t) floor ((hrs * 60.0f * 60.0f * sr) + (mins * 60.0f * sr) + (secs * sr) + (millisecs * sr / 1000.0));
1318 AudioClock::bbt_frame_from_display (framepos_t pos) const
1320 if (_session == 0) {
1321 error << "AudioClock::current_time() called with BBT mode but without session!" << endmsg;
1326 any.type = AnyTime::BBT;
1328 sscanf (_layout->get_text().c_str(), "%" PRId32 "|%" PRId32 "|%" PRId32, &any.bbt.bars, &any.bbt.beats, &any.bbt.ticks);
1333 return _session->any_duration_to_frames (pos, any);
1335 return _session->convert_to_frames (any);
1341 AudioClock::bbt_frame_duration_from_display (framepos_t pos) const
1343 if (_session == 0) {
1344 error << "AudioClock::current_time() called with BBT mode but without session!" << endmsg;
1348 Timecode::BBT_Time bbt;
1350 sscanf (_layout->get_text().c_str(), "%" PRIu32 "|%" PRIu32 "|%" PRIu32, &bbt.bars, &bbt.beats, &bbt.ticks);
1352 return _session->tempo_map().bbt_duration_at(pos,bbt,1);
1356 AudioClock::audio_frame_from_display () const
1359 sscanf (_layout->get_text().c_str(), "%" PRId64, &f);
1364 AudioClock::build_ops_menu ()
1366 using namespace Menu_Helpers;
1367 ops_menu = new Menu;
1368 MenuList& ops_items = ops_menu->items();
1369 ops_menu->set_name ("ArdourContextMenu");
1371 if (!Profile->get_sae()) {
1372 ops_items.push_back (MenuElem (_("Timecode"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), Timecode)));
1374 ops_items.push_back (MenuElem (_("Bars:Beats"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), BBT)));
1375 ops_items.push_back (MenuElem (_("Minutes:Seconds"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), MinSec)));
1376 ops_items.push_back (MenuElem (_("Samples"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), Frames)));
1378 if (editable && !is_duration && !_follows_playhead) {
1379 ops_items.push_back (SeparatorElem());
1380 ops_items.push_back (MenuElem (_("Set From Playhead"), sigc::mem_fun(*this, &AudioClock::set_from_playhead)));
1381 ops_items.push_back (MenuElem (_("Locate to This Time"), sigc::mem_fun(*this, &AudioClock::locate)));
1386 AudioClock::set_from_playhead ()
1392 set (_session->transport_frame());
1397 AudioClock::locate ()
1399 if (!_session || is_duration) {
1403 _session->request_locate (current_time(), _session->transport_rolling ());
1407 AudioClock::set_mode (Mode m)
1417 insert_max = 9; // 8 digits + sign [-]2:2:2:2
1418 mode_based_info_ratio = 0.5;
1422 insert_max = 8; // 8 digits, 2|2|4
1423 mode_based_info_ratio = 0.5;
1427 insert_max = 9; // 7 digits 2:2:2.3
1428 mode_based_info_ratio = 1.0;
1432 insert_max = INT_MAX;
1433 mode_based_info_ratio = 1.0;
1437 set (last_when, true);
1439 if (!is_transient) {
1440 ModeChanged (); /* EMIT SIGNAL (the static one)*/
1443 mode_changed (); /* EMIT SIGNAL (the member one) */
1447 AudioClock::set_bbt_reference (framepos_t pos)
1449 bbt_reference_time = pos;
1453 AudioClock::on_style_changed (const Glib::RefPtr<Gtk::Style>& old_style)
1455 CairoWidget::on_style_changed (old_style);
1461 AudioClock::set_is_duration (bool yn)
1463 if (yn == is_duration) {
1468 set (last_when, true, 0, 's');
1472 AudioClock::set_off (bool yn)
1481 _canonical_time = current_time ();
1482 _canonical_time_is_displayed = false;
1484 _canonical_time_is_displayed = true;
1487 /* force a possible redraw */
1489 set (_canonical_time, true);
1493 AudioClock::focus ()
1499 AudioClock::set_draw_background (bool yn)
1505 AudioClock::timecode_tester ()
1508 #define Timecode_SAMPLE_TEST_1
1509 #define Timecode_SAMPLE_TEST_2
1510 #define Timecode_SAMPLE_TEST_3
1511 #define Timecode_SAMPLE_TEST_4
1512 #define Timecode_SAMPLE_TEST_5
1513 #define Timecode_SAMPLE_TEST_6
1514 #define Timecode_SAMPLE_TEST_7
1516 // Testcode for timecode<->sample conversions (P.S.)
1517 Timecode::Time timecode1;
1519 framepos_t oldsample = 0;
1520 Timecode::Time timecode2;
1521 framecnt_t sample_increment;
1523 sample_increment = (framecnt_t)rint(_session->frame_rate() / _session->timecode_frames_per_second);
1525 #ifdef Timecode_SAMPLE_TEST_1
1526 // Test 1: use_offset = false, use_subframes = false
1527 cout << "use_offset = false, use_subframes = false" << endl;
1528 for (int i = 0; i < 108003; i++) {
1529 _session->timecode_to_sample( timecode1, sample1, false /* use_offset */, false /* use_subframes */ );
1530 _session->sample_to_timecode( sample1, timecode2, false /* use_offset */, false /* use_subframes */ );
1532 if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) {
1533 cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1534 cout << "timecode1: " << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1535 cout << "sample: " << sample1 << endl;
1536 cout << "sample: " << sample1 << " -> ";
1537 cout << "timecode2: " << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1541 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1542 cout << "ERROR: timecode2 not equal timecode1" << endl;
1543 cout << "timecode1: " << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1544 cout << "sample: " << sample1 << endl;
1545 cout << "sample: " << sample1 << " -> ";
1546 cout << "timecode2: " << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1549 oldsample = sample1;
1550 _session->timecode_increment( timecode1 );
1553 cout << "sample_increment: " << sample_increment << endl;
1554 cout << "sample: " << sample1 << " -> ";
1555 cout << "timecode: " << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1558 #ifdef Timecode_SAMPLE_TEST_2
1559 // Test 2: use_offset = true, use_subframes = false
1560 cout << "use_offset = true, use_subframes = false" << endl;
1562 timecode1.hours = 0;
1563 timecode1.minutes = 0;
1564 timecode1.seconds = 0;
1565 timecode1.frames = 0;
1566 timecode1.subframes = 0;
1567 sample1 = oldsample = 0;
1569 _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1570 cout << "Starting at sample: " << sample1 << " -> ";
1571 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1573 for (int i = 0; i < 108003; i++) {
1574 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1575 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1577 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1578 // cout << "sample: " << sample1 << endl;
1579 // cout << "sample: " << sample1 << " -> ";
1580 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1582 if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) {
1583 cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1584 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1585 cout << "sample: " << sample1 << endl;
1586 cout << "sample: " << sample1 << " -> ";
1587 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1591 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1592 cout << "ERROR: timecode2 not equal timecode1" << endl;
1593 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1594 cout << "sample: " << sample1 << endl;
1595 cout << "sample: " << sample1 << " -> ";
1596 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1599 oldsample = sample1;
1600 _session->timecode_increment( timecode1 );
1603 cout << "sample_increment: " << sample_increment << endl;
1604 cout << "sample: " << sample1 << " -> ";
1605 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1608 #ifdef Timecode_SAMPLE_TEST_3
1609 // Test 3: use_offset = true, use_subframes = false, decrement
1610 cout << "use_offset = true, use_subframes = false, decrement" << endl;
1612 _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1613 cout << "Starting at sample: " << sample1 << " -> ";
1614 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1616 for (int i = 0; i < 108003; i++) {
1617 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1618 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1620 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1621 // cout << "sample: " << sample1 << endl;
1622 // cout << "sample: " << sample1 << " -> ";
1623 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1625 if ((i > 0) && ( ((oldsample - sample1) != sample_increment) && ((oldsample - sample1) != (sample_increment + 1)) && ((oldsample - sample1) != (sample_increment - 1)))) {
1626 cout << "ERROR: sample increment not right: " << (oldsample - sample1) << " != " << sample_increment << endl;
1627 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1628 cout << "sample: " << sample1 << endl;
1629 cout << "sample: " << sample1 << " -> ";
1630 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1634 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1635 cout << "ERROR: timecode2 not equal timecode1" << endl;
1636 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1637 cout << "sample: " << sample1 << endl;
1638 cout << "sample: " << sample1 << " -> ";
1639 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1642 oldsample = sample1;
1643 _session->timecode_decrement( timecode1 );
1646 cout << "sample_decrement: " << sample_increment << endl;
1647 cout << "sample: " << sample1 << " -> ";
1648 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1652 #ifdef Timecode_SAMPLE_TEST_4
1653 // Test 4: use_offset = true, use_subframes = true
1654 cout << "use_offset = true, use_subframes = true" << endl;
1656 for (long sub = 5; sub < 80; sub += 5) {
1657 timecode1.hours = 0;
1658 timecode1.minutes = 0;
1659 timecode1.seconds = 0;
1660 timecode1.frames = 0;
1661 timecode1.subframes = 0;
1662 sample1 = oldsample = (sample_increment * sub) / 80;
1664 _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, true /* use_subframes */ );
1666 cout << "starting at sample: " << sample1 << " -> ";
1667 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1669 for (int i = 0; i < 108003; i++) {
1670 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, true /* use_subframes */ );
1671 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, true /* use_subframes */ );
1673 if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) {
1674 cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1675 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1676 cout << "sample: " << sample1 << endl;
1677 cout << "sample: " << sample1 << " -> ";
1678 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1682 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames || timecode2.subframes != timecode1.subframes) {
1683 cout << "ERROR: timecode2 not equal timecode1" << endl;
1684 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1685 cout << "sample: " << sample1 << endl;
1686 cout << "sample: " << sample1 << " -> ";
1687 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1690 oldsample = sample1;
1691 _session->timecode_increment( timecode1 );
1694 cout << "sample_increment: " << sample_increment << endl;
1695 cout << "sample: " << sample1 << " -> ";
1696 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1698 for (int i = 0; i < 108003; i++) {
1699 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, true /* use_subframes */ );
1700 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, true /* use_subframes */ );
1702 if ((i > 0) && ( ((oldsample - sample1) != sample_increment) && ((oldsample - sample1) != (sample_increment + 1)) && ((oldsample - sample1) != (sample_increment - 1)))) {
1703 cout << "ERROR: sample increment not right: " << (oldsample - sample1) << " != " << sample_increment << endl;
1704 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1705 cout << "sample: " << sample1 << endl;
1706 cout << "sample: " << sample1 << " -> ";
1707 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1711 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames || timecode2.subframes != timecode1.subframes) {
1712 cout << "ERROR: timecode2 not equal timecode1" << endl;
1713 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1714 cout << "sample: " << sample1 << endl;
1715 cout << "sample: " << sample1 << " -> ";
1716 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1719 oldsample = sample1;
1720 _session->timecode_decrement( timecode1 );
1723 cout << "sample_decrement: " << sample_increment << endl;
1724 cout << "sample: " << sample1 << " -> ";
1725 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1730 #ifdef Timecode_SAMPLE_TEST_5
1731 // Test 5: use_offset = true, use_subframes = false, increment seconds
1732 cout << "use_offset = true, use_subframes = false, increment seconds" << endl;
1734 timecode1.hours = 0;
1735 timecode1.minutes = 0;
1736 timecode1.seconds = 0;
1737 timecode1.frames = 0;
1738 timecode1.subframes = 0;
1739 sample1 = oldsample = 0;
1740 sample_increment = _session->frame_rate();
1742 _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1743 cout << "Starting at sample: " << sample1 << " -> ";
1744 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1746 for (int i = 0; i < 3600; i++) {
1747 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1748 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1750 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1751 // cout << "sample: " << sample1 << endl;
1752 // cout << "sample: " << sample1 << " -> ";
1753 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1755 // if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1))))
1757 // cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1761 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1762 cout << "ERROR: timecode2 not equal timecode1" << endl;
1763 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1764 cout << "sample: " << sample1 << endl;
1765 cout << "sample: " << sample1 << " -> ";
1766 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1769 oldsample = sample1;
1770 _session->timecode_increment_seconds( timecode1 );
1773 cout << "sample_increment: " << sample_increment << endl;
1774 cout << "sample: " << sample1 << " -> ";
1775 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1779 #ifdef Timecode_SAMPLE_TEST_6
1780 // Test 6: use_offset = true, use_subframes = false, increment minutes
1781 cout << "use_offset = true, use_subframes = false, increment minutes" << endl;
1783 timecode1.hours = 0;
1784 timecode1.minutes = 0;
1785 timecode1.seconds = 0;
1786 timecode1.frames = 0;
1787 timecode1.subframes = 0;
1788 sample1 = oldsample = 0;
1789 sample_increment = _session->frame_rate() * 60;
1791 _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1792 cout << "Starting at sample: " << sample1 << " -> ";
1793 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1795 for (int i = 0; i < 60; i++) {
1796 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1797 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1799 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1800 // cout << "sample: " << sample1 << endl;
1801 // cout << "sample: " << sample1 << " -> ";
1802 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1804 // if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1))))
1806 // cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1810 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1811 cout << "ERROR: timecode2 not equal timecode1" << endl;
1812 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1813 cout << "sample: " << sample1 << endl;
1814 cout << "sample: " << sample1 << " -> ";
1815 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1818 oldsample = sample1;
1819 _session->timecode_increment_minutes( timecode1 );
1822 cout << "sample_increment: " << sample_increment << endl;
1823 cout << "sample: " << sample1 << " -> ";
1824 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1827 #ifdef Timecode_SAMPLE_TEST_7
1828 // Test 7: use_offset = true, use_subframes = false, increment hours
1829 cout << "use_offset = true, use_subframes = false, increment hours" << endl;
1831 timecode1.hours = 0;
1832 timecode1.minutes = 0;
1833 timecode1.seconds = 0;
1834 timecode1.frames = 0;
1835 timecode1.subframes = 0;
1836 sample1 = oldsample = 0;
1837 sample_increment = _session->frame_rate() * 60 * 60;
1839 _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1840 cout << "Starting at sample: " << sample1 << " -> ";
1841 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1843 for (int i = 0; i < 10; i++) {
1844 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1845 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1847 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1848 // cout << "sample: " << sample1 << endl;
1849 // cout << "sample: " << sample1 << " -> ";
1850 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1852 // if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1))))
1854 // cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1858 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1859 cout << "ERROR: timecode2 not equal timecode1" << endl;
1860 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1861 cout << "sample: " << sample1 << endl;
1862 cout << "sample: " << sample1 << " -> ";
1863 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1866 oldsample = sample1;
1867 _session->timecode_increment_hours( timecode1 );
1870 cout << "sample_increment: " << sample_increment << endl;
1871 cout << "sample: " << sample1 << " -> ";
1872 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;