X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Faudio_clock.cc;h=aff72fbf6e0d063976ba34db070f635ca7e98b06;hb=0938a42440cc82ce8d0cb064840c258c863714ab;hp=c27015801f9bffb2f9aec6d8cf433c3808ccc225;hpb=bc89fe0147c04b67141936d109c00dfd4d69cc4b;p=ardour.git diff --git a/gtk2_ardour/audio_clock.cc b/gtk2_ardour/audio_clock.cc index c27015801f..aff72fbf6e 100644 --- a/gtk2_ardour/audio_clock.cc +++ b/gtk2_ardour/audio_clock.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 1999 Paul Davis + Copyright (C) 1999 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,411 +20,317 @@ #include // for sprintf #include -#include -#include +#include "pbd/convert.h" +#include "pbd/enumwriter.h" +#include + +#include "gtkmm2ext/cairocell.h" #include -#include -#include -#include -#include +#include "ardour/ardour.h" +#include "ardour/session.h" +#include "ardour/tempo.h" +#include "ardour/profile.h" #include #include "ardour_ui.h" #include "audio_clock.h" #include "utils.h" #include "keyboard.h" +#include "gui_thread.h" #include "i18n.h" using namespace ARDOUR; using namespace PBD; -using namespace sigc; using namespace Gtk; using namespace std; +using Gtkmm2ext::Keyboard; + using PBD::atoi; using PBD::atof; sigc::signal AudioClock::ModeChanged; vector AudioClock::clocks; -const uint32_t AudioClock::field_length[(int) AudioClock::AudioFrames+1] = { - 2, /* SMPTE_Hours */ - 2, /* SMPTE_Minutes */ - 2, /* SMPTE_Seconds */ - 2, /* SMPTE_Frames */ - 2, /* MS_Hours */ - 2, /* MS_Minutes */ - 5, /* MS_Seconds */ - 3, /* Bars */ - 2, /* Beats */ - 4, /* Tick */ - 10 /* Audio Frame */ +uint32_t AudioClock::field_length[] = { + 1, /* Timecode_Sign */ + 2, /* Timecode_Hours */ + 2, /* Timecode_Minutes */ + 2, /* Timecode_Seconds */ + 2, /* Timecode_Frames */ + 2, /* MS_Hours */ + 2, /* MS_Minutes */ + 2, /* MS_Seconds */ + 3, /* MS_Milliseconds */ + 4, /* Bars */ + 2, /* Beats */ + 4, /* Ticks */ + 10, /* AudioFrames */ }; -AudioClock::AudioClock (std::string clock_name, bool transient, std::string widget_name, bool allow_edit, bool duration, bool with_info) - : _name (clock_name), - is_transient (transient), - is_duration (duration), - editable (allow_edit), - colon1 (":"), - colon2 (":"), - colon3 (":"), - colon4 (":"), - colon5 (":"), - b1 ("|"), - b2 ("|"), - last_when(0) +AudioClock::AudioClock (const string& clock_name, bool transient, const string& widget_name, + bool allow_edit, bool follows_playhead, bool duration, bool with_info) + : _name (clock_name) + , is_transient (transient) + , is_duration (duration) + , editable (allow_edit) + , _follows_playhead (follows_playhead) + , _off (false) + , supplemental_left (0) + , supplemental_right (0) + , last_when(0) + , _canonical_time_is_displayed (true) + , _canonical_time (0) { - session = 0; last_when = 0; + + last_hrs = 9999; + last_mins = 9999; + last_secs = 9999; + last_frames = 99999; + + ms_last_hrs = 9999; + ms_last_mins = 9999; + ms_last_secs = 9999; + ms_last_millisecs = 99999; + + last_negative = false; + last_pdelta = 0; last_sdelta = 0; key_entry_state = 0; ops_menu = 0; dragging = false; bbt_reference_time = -1; + editing_field = (Field) 0; - if (with_info) { - frames_upper_info_label = manage (new Label); - frames_lower_info_label = manage (new Label); - smpte_upper_info_label = manage (new Label); - smpte_lower_info_label = manage (new Label); - bbt_upper_info_label = manage (new Label); - bbt_lower_info_label = manage (new Label); - - frames_upper_info_label->set_name ("AudioClockFramesUpperInfo"); - frames_lower_info_label->set_name ("AudioClockFramesLowerInfo"); - smpte_upper_info_label->set_name ("AudioClockSMPTEUpperInfo"); - smpte_lower_info_label->set_name ("AudioClockSMPTELowerInfo"); - bbt_upper_info_label->set_name ("AudioClockBBTUpperInfo"); - bbt_lower_info_label->set_name ("AudioClockBBTLowerInfo"); - - Gtkmm2ext::set_size_request_to_display_given_text(*smpte_upper_info_label, "23.98",0,0); - Gtkmm2ext::set_size_request_to_display_given_text(*smpte_lower_info_label, "NDF",0,0); - - Gtkmm2ext::set_size_request_to_display_given_text(*bbt_upper_info_label, "88|88",0,0); - Gtkmm2ext::set_size_request_to_display_given_text(*bbt_lower_info_label, "888.88",0,0); - - frames_info_box.pack_start (*frames_upper_info_label, true, true); - frames_info_box.pack_start (*frames_lower_info_label, true, true); - smpte_info_box.pack_start (*smpte_upper_info_label, true, true); - smpte_info_box.pack_start (*smpte_lower_info_label, true, true); - bbt_info_box.pack_start (*bbt_upper_info_label, true, true); - bbt_info_box.pack_start (*bbt_lower_info_label, true, true); - - } else { - frames_upper_info_label = 0; - frames_lower_info_label = 0; - smpte_upper_info_label = 0; - smpte_lower_info_label = 0; - bbt_upper_info_label = 0; - bbt_lower_info_label = 0; - } - - audio_frames_ebox.add (audio_frames_label); - - frames_packer.set_homogeneous (false); - frames_packer.set_border_width (2); - frames_packer.pack_start (audio_frames_ebox, false, false); + /* basic per-mode editable text "arrays" */ + + display = new CairoEditableText (); + display->set_corner_radius (0); + + _fixed_cells[Colon1] = new CairoCharCell (Colon1, ':'); + _fixed_cells[Colon2] = new CairoCharCell (Colon2, ':'); + _fixed_cells[Colon3] = new CairoCharCell (Colon3, ':'); + _fixed_cells[Bar1] = new CairoCharCell (Bar1, '|'); + _fixed_cells[Bar2] = new CairoCharCell (Bar2, '|'); - if (with_info) { - frames_packer.pack_start (frames_info_box, false, false, 5); - } + _text_cells[Timecode_Sign] = new CairoTextCell (Timecode_Sign, field_length[Timecode_Sign]); + _text_cells[Timecode_Hours] = new CairoTextCell (Timecode_Hours, field_length[Timecode_Hours]); + _text_cells[Timecode_Minutes] = new CairoTextCell (Timecode_Minutes, field_length[Timecode_Minutes]); + _text_cells[Timecode_Seconds] = new CairoTextCell (Timecode_Seconds, field_length[Timecode_Seconds]); + _text_cells[Timecode_Frames] = new CairoTextCell (Timecode_Frames, field_length[Timecode_Frames]); + + /* Minutes/Seconds */ - frames_packer_hbox.pack_start (frames_packer, true, false); - - hours_ebox.add (hours_label); - minutes_ebox.add (minutes_label); - seconds_ebox.add (seconds_label); - frames_ebox.add (frames_label); - bars_ebox.add (bars_label); - beats_ebox.add (beats_label); - ticks_ebox.add (ticks_label); - ms_hours_ebox.add (ms_hours_label); - ms_minutes_ebox.add (ms_minutes_label); - ms_seconds_ebox.add (ms_seconds_label); - - smpte_packer.set_homogeneous (false); - smpte_packer.set_border_width (2); - smpte_packer.pack_start (hours_ebox, false, false); - smpte_packer.pack_start (colon1, false, false); - smpte_packer.pack_start (minutes_ebox, false, false); - smpte_packer.pack_start (colon2, false, false); - smpte_packer.pack_start (seconds_ebox, false, false); - smpte_packer.pack_start (colon3, false, false); - smpte_packer.pack_start (frames_ebox, false, false); + _text_cells[MS_Hours] = new CairoTextCell (MS_Hours, field_length[MS_Hours]); + _text_cells[MS_Minutes] = new CairoTextCell (MS_Minutes, field_length[MS_Minutes]); + _text_cells[MS_Seconds] = new CairoTextCell (MS_Seconds, field_length[MS_Seconds]); + _text_cells[MS_Milliseconds] = new CairoTextCell (MS_Milliseconds, field_length[MS_Milliseconds]); - if (with_info) { - smpte_packer.pack_start (smpte_info_box, false, false, 5); - } + /* Beats/Bars/Ticks */ + + _text_cells[Bars] = new CairoTextCell (Bars, field_length[Bars]); + _text_cells[Beats] = new CairoTextCell (Beats, field_length[Beats]); + _text_cells[Ticks] = new CairoTextCell (Ticks, field_length[Ticks]); - smpte_packer_hbox.pack_start (smpte_packer, true, false); + /* Audio Frames */ + + _text_cells[AudioFrames] = new CairoTextCell (AudioFrames, field_length[AudioFrames]); - bbt_packer.set_homogeneous (false); - bbt_packer.set_border_width (2); - bbt_packer.pack_start (bars_ebox, false, false); - bbt_packer.pack_start (b1, false, false); - bbt_packer.pack_start (beats_ebox, false, false); - bbt_packer.pack_start (b2, false, false); - bbt_packer.pack_start (ticks_ebox, false, false); + set_homogeneous (false); if (with_info) { - bbt_packer.pack_start (bbt_info_box, false, false, 5); - } - bbt_packer_hbox.pack_start (bbt_packer, true, false); + supplemental_left = new CairoEditableText (); + supplemental_right = new CairoEditableText (); + + supplemental_left->set_corner_radius (0); + supplemental_right->set_corner_radius (0); - minsec_packer.set_homogeneous (false); - minsec_packer.set_border_width (2); - minsec_packer.pack_start (ms_hours_ebox, false, false); - minsec_packer.pack_start (colon4, false, false); - minsec_packer.pack_start (ms_minutes_ebox, false, false); - minsec_packer.pack_start (colon5, false, false); - minsec_packer.pack_start (ms_seconds_ebox, false, false); + /* field lengths of these cells will be set dynamically by ::set_mode() + */ - minsec_packer_hbox.pack_start (minsec_packer, true, false); + _text_cells[LowerLeft1] = new CairoTextCell (LowerLeft1, 0); + _text_cells[LowerLeft2] = new CairoTextCell (LowerLeft2, 0); + _text_cells[LowerRight1] = new CairoTextCell (LowerRight1, 0); + _text_cells[LowerRight2] = new CairoTextCell (LowerRight2, 0); + + bottom.set_spacing (1); + bottom.set_homogeneous (false); + bottom.pack_start (*supplemental_left, true, true); + bottom.pack_start (*supplemental_right, true, true); - clock_frame.set_shadow_type (Gtk::SHADOW_IN); - clock_frame.set_name ("BaseFrame"); + top.pack_start (*display, true, true); + + set_spacing (1); + + pack_start (top, true, true); + pack_start (bottom, true, true); + } else { + pack_start (*display, true, true); + } - clock_frame.add (clock_base); + show_all (); set_widget_name (widget_name); _mode = BBT; /* lie to force mode switch */ - set_mode (SMPTE); - - pack_start (clock_frame, true, true); + set_mode (Timecode); + set (last_when, true); - /* the clock base handles button releases for menu popup regardless of - editable status. if the clock is editable, the clock base is where - we pass focus to after leaving the last editable "field", which - will then shutdown editing till the user starts it up again. + connect_signals (); - it does this because the focus out event on the field disables - keyboard event handling, and we don't connect anything up to - notice focus in on the clock base. hence, keyboard event handling - stays disabled. + if (!is_transient) { + clocks.push_back (this); + } +} + +AudioClock::~AudioClock () +{ + /* these are not manage()'d, so that we can add/remove + them from containers as necessary. */ - clock_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::SCROLL_MASK); - clock_base.signal_button_release_event().connect (bind (mem_fun (*this, &AudioClock::field_button_release_event), SMPTE_Hours)); - - Session::SMPTEOffsetChanged.connect (mem_fun (*this, &AudioClock::smpte_offset_changed)); + delete display; + delete supplemental_left; + delete supplemental_right; - if (editable) { - setup_events (); + for (std::map::iterator i = _fixed_cells.begin(); i != _fixed_cells.end(); ++i) { + delete i->second; } - set (last_when, true); - - if (!is_transient) { - clocks.push_back (this); + for (std::map::iterator i = _text_cells.begin(); i != _text_cells.end(); ++i) { + delete i->second; } } void -AudioClock::set_widget_name (string name) +AudioClock::set_widget_name (const string& name) { Widget::set_name (name); - clock_base.set_name (name); - - audio_frames_label.set_name (name); - hours_label.set_name (name); - minutes_label.set_name (name); - seconds_label.set_name (name); - frames_label.set_name (name); - bars_label.set_name (name); - beats_label.set_name (name); - ticks_label.set_name (name); - ms_hours_label.set_name (name); - ms_minutes_label.set_name (name); - ms_seconds_label.set_name (name); - hours_ebox.set_name (name); - minutes_ebox.set_name (name); - seconds_ebox.set_name (name); - frames_ebox.set_name (name); - audio_frames_ebox.set_name (name); - bars_ebox.set_name (name); - beats_ebox.set_name (name); - ticks_ebox.set_name (name); - ms_hours_ebox.set_name (name); - ms_minutes_ebox.set_name (name); - ms_seconds_ebox.set_name (name); - - colon1.set_name (name); - colon2.set_name (name); - colon3.set_name (name); - colon4.set_name (name); - colon5.set_name (name); - b1.set_name (name); - b2.set_name (name); + set_theme (); +} + +void +AudioClock::set_theme () +{ + Glib::RefPtr style = get_style (); + double r, g, b, a; + + if (!style) { + return; + } + + Pango::FontDescription font; + + if (!is_realized()) { + font = get_font_for_style (get_name()); + } else { + font = style->get_font(); + } + + display->set_font (font); + + + if (supplemental_left) { + /* propagate font style, sort of, into supplemental text */ + boost::shared_ptr smaller_font (new CairoFontDescription (*display->font().get())); + smaller_font->set_size (12); + smaller_font->set_weight (Cairo::FONT_WEIGHT_NORMAL); + supplemental_right->set_font (smaller_font); + supplemental_left->set_font (smaller_font); + } + + Gdk::Color bg = style->get_base (Gtk::STATE_NORMAL); + Gdk::Color fg = style->get_text (Gtk::STATE_NORMAL); + Gdk::Color eg = style->get_text (Gtk::STATE_ACTIVE); + + r = bg.get_red_p (); + g = bg.get_green_p (); + b = bg.get_blue_p (); + a = 1.0; + + display->set_bg (r, g, b, a); + + if (supplemental_right) { + supplemental_right->set_bg (r,g,b,a); + supplemental_left->set_bg (r,g,b,a); + } + + r = fg.get_red_p (); + g = fg.get_green_p (); + b = fg.get_blue_p (); + a = 1.0; + + display->set_colors (r, g, b, a); + + if (supplemental_right) { + supplemental_right->set_colors (r,g,b,a); + supplemental_left->set_colors (r,g,b,a); + } + + r = eg.get_red_p (); + g = eg.get_green_p (); + b = eg.get_blue_p (); + a = 1.0; + + display->set_edit_colors (r, g, b, a); + + if (supplemental_right) { + supplemental_right->set_edit_colors (r,g,b,a); + supplemental_left->set_edit_colors (r,g,b,a); + } queue_draw (); } void -AudioClock::setup_events () +AudioClock::focus () { - clock_base.set_flags (Gtk::CAN_FOCUS); - - hours_ebox.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK); - minutes_ebox.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK); - seconds_ebox.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK); - frames_ebox.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK); - bars_ebox.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK); - beats_ebox.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK); - ticks_ebox.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK); - ms_hours_ebox.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK); - ms_minutes_ebox.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK); - ms_seconds_ebox.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK); - audio_frames_ebox.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK); - - hours_ebox.set_flags (Gtk::CAN_FOCUS); - minutes_ebox.set_flags (Gtk::CAN_FOCUS); - seconds_ebox.set_flags (Gtk::CAN_FOCUS); - frames_ebox.set_flags (Gtk::CAN_FOCUS); - audio_frames_ebox.set_flags (Gtk::CAN_FOCUS); - bars_ebox.set_flags (Gtk::CAN_FOCUS); - beats_ebox.set_flags (Gtk::CAN_FOCUS); - ticks_ebox.set_flags (Gtk::CAN_FOCUS); - ms_hours_ebox.set_flags (Gtk::CAN_FOCUS); - ms_minutes_ebox.set_flags (Gtk::CAN_FOCUS); - ms_seconds_ebox.set_flags (Gtk::CAN_FOCUS); - - hours_ebox.signal_motion_notify_event().connect (bind (mem_fun(*this, &AudioClock::field_motion_notify_event), SMPTE_Hours)); - minutes_ebox.signal_motion_notify_event().connect (bind (mem_fun(*this, &AudioClock::field_motion_notify_event), SMPTE_Minutes)); - seconds_ebox.signal_motion_notify_event().connect (bind (mem_fun(*this, &AudioClock::field_motion_notify_event), SMPTE_Seconds)); - frames_ebox.signal_motion_notify_event().connect (bind (mem_fun(*this, &AudioClock::field_motion_notify_event), SMPTE_Frames)); - audio_frames_ebox.signal_motion_notify_event().connect (bind (mem_fun(*this, &AudioClock::field_motion_notify_event), AudioFrames)); - bars_ebox.signal_motion_notify_event().connect (bind (mem_fun(*this, &AudioClock::field_motion_notify_event), Bars)); - beats_ebox.signal_motion_notify_event().connect (bind (mem_fun(*this, &AudioClock::field_motion_notify_event), Beats)); - ticks_ebox.signal_motion_notify_event().connect (bind (mem_fun(*this, &AudioClock::field_motion_notify_event), Ticks)); - ms_hours_ebox.signal_motion_notify_event().connect (bind (mem_fun(*this, &AudioClock::field_motion_notify_event), MS_Hours)); - ms_minutes_ebox.signal_motion_notify_event().connect (bind (mem_fun(*this, &AudioClock::field_motion_notify_event), MS_Minutes)); - ms_seconds_ebox.signal_motion_notify_event().connect (bind (mem_fun(*this, &AudioClock::field_motion_notify_event), MS_Seconds)); - - hours_ebox.signal_button_press_event().connect (bind (mem_fun(*this, &AudioClock::field_button_press_event), SMPTE_Hours)); - minutes_ebox.signal_button_press_event().connect (bind (mem_fun(*this, &AudioClock::field_button_press_event), SMPTE_Minutes)); - seconds_ebox.signal_button_press_event().connect (bind (mem_fun(*this, &AudioClock::field_button_press_event), SMPTE_Seconds)); - frames_ebox.signal_button_press_event().connect (bind (mem_fun(*this, &AudioClock::field_button_press_event), SMPTE_Frames)); - audio_frames_ebox.signal_button_press_event().connect (bind (mem_fun(*this, &AudioClock::field_button_press_event), AudioFrames)); - bars_ebox.signal_button_press_event().connect (bind (mem_fun(*this, &AudioClock::field_button_press_event), Bars)); - beats_ebox.signal_button_press_event().connect (bind (mem_fun(*this, &AudioClock::field_button_press_event), Beats)); - ticks_ebox.signal_button_press_event().connect (bind (mem_fun(*this, &AudioClock::field_button_press_event), Ticks)); - ms_hours_ebox.signal_button_press_event().connect (bind (mem_fun(*this, &AudioClock::field_button_press_event), MS_Hours)); - ms_minutes_ebox.signal_button_press_event().connect (bind (mem_fun(*this, &AudioClock::field_button_press_event), MS_Minutes)); - ms_seconds_ebox.signal_button_press_event().connect (bind (mem_fun(*this, &AudioClock::field_button_press_event), MS_Seconds)); - - hours_ebox.signal_button_release_event().connect (bind (mem_fun(*this, &AudioClock::field_button_release_event), SMPTE_Hours)); - minutes_ebox.signal_button_release_event().connect (bind (mem_fun(*this, &AudioClock::field_button_release_event), SMPTE_Minutes)); - seconds_ebox.signal_button_release_event().connect (bind (mem_fun(*this, &AudioClock::field_button_release_event), SMPTE_Seconds)); - frames_ebox.signal_button_release_event().connect (bind (mem_fun(*this, &AudioClock::field_button_release_event), SMPTE_Frames)); - audio_frames_ebox.signal_button_release_event().connect (bind (mem_fun(*this, &AudioClock::field_button_release_event), AudioFrames)); - bars_ebox.signal_button_release_event().connect (bind (mem_fun(*this, &AudioClock::field_button_release_event), Bars)); - beats_ebox.signal_button_release_event().connect (bind (mem_fun(*this, &AudioClock::field_button_release_event), Beats)); - ticks_ebox.signal_button_release_event().connect (bind (mem_fun(*this, &AudioClock::field_button_release_event), Ticks)); - ms_hours_ebox.signal_button_release_event().connect (bind (mem_fun(*this, &AudioClock::field_button_release_event), MS_Hours)); - ms_minutes_ebox.signal_button_release_event().connect (bind (mem_fun(*this, &AudioClock::field_button_release_event), MS_Minutes)); - ms_seconds_ebox.signal_button_release_event().connect (bind (mem_fun(*this, &AudioClock::field_button_release_event), MS_Seconds)); - - hours_ebox.signal_scroll_event().connect (bind (mem_fun(*this, &AudioClock::field_button_scroll_event), SMPTE_Hours)); - minutes_ebox.signal_scroll_event().connect (bind (mem_fun(*this, &AudioClock::field_button_scroll_event), SMPTE_Minutes)); - seconds_ebox.signal_scroll_event().connect (bind (mem_fun(*this, &AudioClock::field_button_scroll_event), SMPTE_Seconds)); - frames_ebox.signal_scroll_event().connect (bind (mem_fun(*this, &AudioClock::field_button_scroll_event), SMPTE_Frames)); - audio_frames_ebox.signal_scroll_event().connect (bind (mem_fun(*this, &AudioClock::field_button_scroll_event), AudioFrames)); - bars_ebox.signal_scroll_event().connect (bind (mem_fun(*this, &AudioClock::field_button_scroll_event), Bars)); - beats_ebox.signal_scroll_event().connect (bind (mem_fun(*this, &AudioClock::field_button_scroll_event), Beats)); - ticks_ebox.signal_scroll_event().connect (bind (mem_fun(*this, &AudioClock::field_button_scroll_event), Ticks)); - ms_hours_ebox.signal_scroll_event().connect (bind (mem_fun(*this, &AudioClock::field_button_scroll_event), MS_Hours)); - ms_minutes_ebox.signal_scroll_event().connect (bind (mem_fun(*this, &AudioClock::field_button_scroll_event), MS_Minutes)); - ms_seconds_ebox.signal_scroll_event().connect (bind (mem_fun(*this, &AudioClock::field_button_scroll_event), MS_Seconds)); - - hours_ebox.signal_key_press_event().connect (bind (mem_fun(*this, &AudioClock::field_key_press_event), SMPTE_Hours)); - minutes_ebox.signal_key_press_event().connect (bind (mem_fun(*this, &AudioClock::field_key_press_event), SMPTE_Minutes)); - seconds_ebox.signal_key_press_event().connect (bind (mem_fun(*this, &AudioClock::field_key_press_event), SMPTE_Seconds)); - frames_ebox.signal_key_press_event().connect (bind (mem_fun(*this, &AudioClock::field_key_press_event), SMPTE_Frames)); - audio_frames_ebox.signal_key_press_event().connect (bind (mem_fun(*this, &AudioClock::field_key_press_event), AudioFrames)); - bars_ebox.signal_key_press_event().connect (bind (mem_fun(*this, &AudioClock::field_key_press_event), Bars)); - beats_ebox.signal_key_press_event().connect (bind (mem_fun(*this, &AudioClock::field_key_press_event), Beats)); - ticks_ebox.signal_key_press_event().connect (bind (mem_fun(*this, &AudioClock::field_key_press_event), Ticks)); - ms_hours_ebox.signal_key_press_event().connect (bind (mem_fun(*this, &AudioClock::field_key_press_event), MS_Hours)); - ms_minutes_ebox.signal_key_press_event().connect (bind (mem_fun(*this, &AudioClock::field_key_press_event), MS_Minutes)); - ms_seconds_ebox.signal_key_press_event().connect (bind (mem_fun(*this, &AudioClock::field_key_press_event), MS_Seconds)); - - hours_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), SMPTE_Hours)); - minutes_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), SMPTE_Minutes)); - seconds_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), SMPTE_Seconds)); - frames_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), SMPTE_Frames)); - audio_frames_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), AudioFrames)); - bars_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), Bars)); - beats_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), Beats)); - ticks_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), Ticks)); - ms_hours_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), MS_Hours)); - ms_minutes_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), MS_Minutes)); - ms_seconds_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), MS_Seconds)); - - hours_ebox.signal_focus_in_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_in_event), SMPTE_Hours)); - minutes_ebox.signal_focus_in_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_in_event), SMPTE_Minutes)); - seconds_ebox.signal_focus_in_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_in_event), SMPTE_Seconds)); - frames_ebox.signal_focus_in_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_in_event), SMPTE_Frames)); - audio_frames_ebox.signal_focus_in_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_in_event), AudioFrames)); - bars_ebox.signal_focus_in_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_in_event), Bars)); - beats_ebox.signal_focus_in_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_in_event), Beats)); - ticks_ebox.signal_focus_in_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_in_event), Ticks)); - ms_hours_ebox.signal_focus_in_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_in_event), MS_Hours)); - ms_minutes_ebox.signal_focus_in_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_in_event), MS_Minutes)); - ms_seconds_ebox.signal_focus_in_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_in_event), MS_Seconds)); - - hours_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), SMPTE_Hours)); - minutes_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), SMPTE_Minutes)); - seconds_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), SMPTE_Seconds)); - frames_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), SMPTE_Frames)); - audio_frames_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), AudioFrames)); - bars_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), Bars)); - beats_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), Beats)); - ticks_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), Ticks)); - ms_hours_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), MS_Hours)); - ms_minutes_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), MS_Minutes)); - ms_seconds_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), MS_Seconds)); - - clock_base.signal_focus_in_event().connect (mem_fun (*this, &AudioClock::drop_focus_handler)); } -bool -AudioClock::drop_focus_handler (GdkEventFocus* ignored) +void +AudioClock::end_edit () { + display->stop_editing (); + editing_field = (Field) 0; + key_entry_state = 0; + + /* move focus back to the default widget in the top level window */ + Keyboard::magic_widget_drop_focus (); - return false; + + Widget* top = get_toplevel(); + + if (top->is_toplevel ()) { + Window* win = dynamic_cast (top); + win->grab_focus (); + } } void AudioClock::on_realize () { - HBox::on_realize (); + VBox::on_realize (); /* styles are not available until the widgets are bound to a window */ - - set_size_requests (); + + set_theme (); } void -AudioClock::set (nframes_t when, bool force, nframes_t offset, char which) +AudioClock::set (framepos_t when, bool force, framecnt_t offset, char which) { - - if ((!force && !is_visible()) || session == 0) { - return; - } - - if (when == last_when && !offset && !force) { + if ((!force && !is_visible()) || _session == 0) { return; } - bool pdelta = Config->get_primary_clock_delta_edit_cursor(); - bool sdelta = Config->get_secondary_clock_delta_edit_cursor(); + bool const pdelta = Config->get_primary_clock_delta_edit_cursor (); + bool const sdelta = Config->get_secondary_clock_delta_edit_cursor (); if (offset && which == 'p' && pdelta) { when = (when > offset) ? when - offset : offset - when; @@ -432,13 +338,17 @@ AudioClock::set (nframes_t when, bool force, nframes_t offset, char which) when = (when > offset) ? when - offset : offset - when; } + if (when == last_when && !force) { + return; + } + if (which == 'p' && pdelta && !last_pdelta) { set_widget_name("TransportClockDisplayDelta"); last_pdelta = true; } else if (which == 'p' && !pdelta && last_pdelta) { set_widget_name("TransportClockDisplay"); last_pdelta = false; - } else if (which == 's' && sdelta && !last_sdelta) { + } else if (which == 's' && sdelta && !last_sdelta) { set_widget_name("SecondaryClockDisplayDelta"); last_sdelta = true; } else if (which == 's' && !sdelta && last_sdelta) { @@ -447,8 +357,8 @@ AudioClock::set (nframes_t when, bool force, nframes_t offset, char which) } switch (_mode) { - case SMPTE: - set_smpte (when, force); + case Timecode: + set_timecode (when, force); break; case BBT: @@ -462,23 +372,28 @@ AudioClock::set (nframes_t when, bool force, nframes_t offset, char which) case Frames: set_frames (when, force); break; - - case Off: - break; } last_when = when; + + /* we're setting the time from a frames value, so keep it as the canonical value */ + _canonical_time = when; + _canonical_time_is_displayed = false; } void -AudioClock::smpte_offset_changed () +AudioClock::session_configuration_changed (std::string p) { - nframes_t current; + if (p != "timecode-offset" && p != "timecode-offset-negative") { + return; + } + + framecnt_t current; switch (_mode) { - case SMPTE: + case Timecode: if (is_duration) { - current = current_duration(); + current = current_duration (); } else { current = current_time (); } @@ -490,182 +405,225 @@ AudioClock::smpte_offset_changed () } void -AudioClock::set_frames (nframes_t when, bool force) +AudioClock::set_frames (framepos_t when, bool /*force*/) { char buf[32]; - snprintf (buf, sizeof (buf), "%u", when); - audio_frames_label.set_text (buf); - - if (frames_upper_info_label) { - nframes_t rate = session->frame_rate(); + snprintf (buf, sizeof (buf), "%" PRId64, when); + + if (_off) { + display->set_text (_text_cells[AudioFrames], "-----------"); + + if (supplemental_left) { + supplemental_left->set_text (_text_cells[LowerLeft2], ""); + supplemental_right->set_text (_text_cells[LowerRight2], ""); + } + return; + } + + + display->set_text (_text_cells[AudioFrames], buf); + + if (supplemental_left) { + framecnt_t rate = _session->frame_rate(); + if (fmod (rate, 1000.0) == 0.000) { - sprintf (buf, "%uK", rate/1000); + sprintf (buf, "%" PRId64 "K", rate/1000); } else { - sprintf (buf, "%.3fK", rate/1000.0f); + sprintf (buf, "%" PRId64, rate); } - - if (frames_upper_info_label->get_text() != buf) { - frames_upper_info_label->set_text (buf); - } - - float vid_pullup = Config->get_video_pullup(); - + + supplemental_left->set_text (_text_cells[LowerLeft2], buf); + + float vid_pullup = _session->config.get_video_pullup(); + if (vid_pullup == 0.0) { - if (frames_lower_info_label->get_text () != _("none")) { - frames_lower_info_label->set_text(_("none")); - } + supplemental_right->set_text (_text_cells[LowerRight2], _("none")); } else { sprintf (buf, "%-6.4f", vid_pullup); - if (frames_lower_info_label->get_text() != buf) { - frames_lower_info_label->set_text (buf); - } + supplemental_right->set_text (_text_cells[LowerRight2], buf); } } -} +} void -AudioClock::set_minsec (nframes_t when, bool force) +AudioClock::set_minsec (framepos_t when, bool force) { char buf[32]; - nframes_t left; + framecnt_t left; int hrs; int mins; - float secs; - + int secs; + int millisecs; + + if (_off) { + display->set_text (_text_cells[MS_Hours], "--"); + display->set_text (_text_cells[MS_Minutes], "--"); + display->set_text (_text_cells[MS_Seconds], "--"); + display->set_text (_text_cells[MS_Milliseconds], "--"); + + if (supplemental_left) { + supplemental_left->set_text (_text_cells[LowerLeft2], ""); + supplemental_right->set_text (_text_cells[LowerRight2], ""); + } + + return; + } + left = when; - hrs = (int) floor (left / (session->frame_rate() * 60.0f * 60.0f)); - left -= (nframes_t) floor (hrs * session->frame_rate() * 60.0f * 60.0f); - mins = (int) floor (left / (session->frame_rate() * 60.0f)); - left -= (nframes_t) floor (mins * session->frame_rate() * 60.0f); - secs = left / (float) session->frame_rate(); + hrs = (int) floor (left / (_session->frame_rate() * 60.0f * 60.0f)); + left -= (framecnt_t) floor (hrs * _session->frame_rate() * 60.0f * 60.0f); + mins = (int) floor (left / (_session->frame_rate() * 60.0f)); + left -= (framecnt_t) floor (mins * _session->frame_rate() * 60.0f); + secs = (int) floor (left / (float) _session->frame_rate()); + left -= (framecnt_t) floor (secs * _session->frame_rate()); + millisecs = floor (left * 1000.0 / (float) _session->frame_rate()); if (force || hrs != ms_last_hrs) { sprintf (buf, "%02d", hrs); - ms_hours_label.set_text (buf); + display->set_text (_text_cells[MS_Hours], buf); ms_last_hrs = hrs; } if (force || mins != ms_last_mins) { sprintf (buf, "%02d", mins); - ms_minutes_label.set_text (buf); + display->set_text (_text_cells[MS_Minutes], buf); ms_last_mins = mins; } if (force || secs != ms_last_secs) { - sprintf (buf, "%06.3f", secs); - ms_seconds_label.set_text (buf); + sprintf (buf, "%02d", secs); + display->set_text (_text_cells[MS_Seconds], buf); ms_last_secs = secs; } + + if (force || millisecs != ms_last_millisecs) { + sprintf (buf, "%03d", millisecs); + display->set_text (_text_cells[MS_Milliseconds], buf); + ms_last_millisecs = millisecs; + } } void -AudioClock::set_smpte (nframes_t when, bool force) +AudioClock::set_timecode (framepos_t when, bool force) { char buf[32]; - SMPTE::Time smpte; - + Timecode::Time TC; + + if (_off) { + display->set_text (_text_cells[Timecode_Sign], ""); + display->set_text (_text_cells[Timecode_Hours], "--"); + display->set_text (_text_cells[Timecode_Minutes], "--"); + display->set_text (_text_cells[Timecode_Seconds], "--"); + display->set_text (_text_cells[Timecode_Frames], "--"); + + if (supplemental_left) { + supplemental_left->set_text (_text_cells[LowerLeft2], ""); + supplemental_right->set_text (_text_cells[LowerRight2], ""); + } + + return; + } + if (is_duration) { - session->smpte_duration (when, smpte); + _session->timecode_duration (when, TC); } else { - session->smpte_time (when, smpte); + _session->timecode_time (when, TC); } - if (force || smpte.hours != last_hrs || smpte.negative != last_negative) { - if (smpte.negative) { - sprintf (buf, "-%02" PRIu32, smpte.hours); + if (force || TC.hours != last_hrs || TC.negative != last_negative) { + if (TC.negative) { + display->set_text (_text_cells[Timecode_Sign], "-"); + sprintf (buf, "%0*" PRIu32, field_length[Timecode_Hours], TC.hours); } else { - sprintf (buf, " %02" PRIu32, smpte.hours); + display->set_text (_text_cells[Timecode_Sign], " "); + sprintf (buf, "%0*" PRIu32, field_length[Timecode_Hours], TC.hours); } - hours_label.set_text (buf); - last_hrs = smpte.hours; - last_negative = smpte.negative; + display->set_text (_text_cells[Timecode_Hours], buf); + last_hrs = TC.hours; + last_negative = TC.negative; } - if (force || smpte.minutes != last_mins) { - sprintf (buf, "%02" PRIu32, smpte.minutes); - minutes_label.set_text (buf); - last_mins = smpte.minutes; + if (force || TC.minutes != last_mins) { + sprintf (buf, "%0*" PRIu32, field_length[Timecode_Minutes], TC.minutes); + display->set_text (_text_cells[Timecode_Minutes], buf); + last_mins = TC.minutes; } - if (force || smpte.seconds != last_secs) { - sprintf (buf, "%02" PRIu32, smpte.seconds); - seconds_label.set_text (buf); - last_secs = smpte.seconds; + if (force || TC.seconds != last_secs) { + sprintf (buf, "%0*" PRIu32, field_length[Timecode_Seconds], TC.seconds); + display->set_text (_text_cells[Timecode_Seconds], buf); + last_secs = TC.seconds; } - if (force || smpte.frames != last_frames) { - sprintf (buf, "%02" PRIu32, smpte.frames); - frames_label.set_text (buf); - last_frames = smpte.frames; + if (force || TC.frames != last_frames) { + sprintf (buf, "%0*" PRIu32, field_length[Timecode_Frames], TC.frames); + display->set_text (_text_cells[Timecode_Frames], buf); + last_frames = TC.frames; } + + if (supplemental_right) { + double timecode_frames = _session->timecode_frames_per_second(); - if (smpte_upper_info_label) { - double smpte_frames = session->smpte_frames_per_second(); - - if ( fmod(smpte_frames, 1.0) == 0.0) { - sprintf (buf, "%u", int (smpte_frames)); - } else { - sprintf (buf, "%.2f", smpte_frames); - } - - if (smpte_upper_info_label->get_text() != buf) { - smpte_upper_info_label->set_text (buf); - } - - if ((fabs(smpte_frames - 29.97) < 0.0001) || smpte_frames == 30) { - if (session->smpte_drop_frames()) { - sprintf (buf, "DF"); - } else { - sprintf (buf, "NDF"); - } + if (fmod(timecode_frames, 1.0) == 0.0) { + sprintf (buf, "%u %s", int (timecode_frames), (_session->timecode_drop_frames() ? "D" : "")); } else { - // there is no drop frame alternative - buf[0] = '\0'; - } - - if (smpte_lower_info_label->get_text() != buf) { - smpte_lower_info_label->set_text (buf); + sprintf (buf, "%.2f %s", timecode_frames, (_session->timecode_drop_frames() ? "D" : "")); } + + supplemental_right->set_text (_text_cells[LowerRight2], buf); } } void -AudioClock::set_bbt (nframes_t when, bool force) +AudioClock::set_bbt (framepos_t when, bool force) { char buf[16]; - BBT_Time bbt; + Timecode::BBT_Time BBT; + + if (_off) { + display->set_text (_text_cells[Bars], "--"); + display->set_text (_text_cells[Beats], "--"); + display->set_text (_text_cells[Ticks], "--"); + + if (supplemental_left) { + supplemental_left->set_text (_text_cells[LowerLeft2], ""); + supplemental_right->set_text (_text_cells[LowerRight2], ""); + } + + return; + } /* handle a common case */ if (is_duration) { if (when == 0) { - bbt.bars = 0; - bbt.beats = 0; - bbt.ticks = 0; + BBT.bars = 0; + BBT.beats = 0; + BBT.ticks = 0; } else { - session->tempo_map().bbt_time (when, bbt); - bbt.bars--; - bbt.beats--; + _session->tempo_map().bbt_time (when, BBT); + BBT.bars--; + BBT.beats--; } } else { - session->tempo_map().bbt_time (when, bbt); + _session->tempo_map().bbt_time (when, BBT); } - sprintf (buf, "%03" PRIu32, bbt.bars); - if (force || bars_label.get_text () != buf) { - bars_label.set_text (buf); + sprintf (buf, "%0*" PRIu32, field_length[Bars], BBT.bars); + if (force || _text_cells[Bars]->get_text () != buf) { + display->set_text (_text_cells[Bars], buf); } - sprintf (buf, "%02" PRIu32, bbt.beats); - if (force || beats_label.get_text () != buf) { - beats_label.set_text (buf); + sprintf (buf, "%0*" PRIu32, field_length[Beats], BBT.beats); + if (force || _text_cells[Beats]->get_text () != buf) { + display->set_text (_text_cells[Beats], buf); } - sprintf (buf, "%04" PRIu32, bbt.ticks); - if (force || ticks_label.get_text () != buf) { - ticks_label.set_text (buf); + sprintf (buf, "%0*" PRIu32, field_length[Ticks], BBT.ticks); + if (force || _text_cells[Ticks]->get_text () != buf) { + display->set_text (_text_cells[Ticks], buf); } - - if (bbt_upper_info_label) { - nframes64_t pos; + + if (supplemental_right) { + framepos_t pos; if (bbt_reference_time < 0) { pos = when; @@ -673,34 +631,42 @@ AudioClock::set_bbt (nframes_t when, bool force) pos = bbt_reference_time; } - TempoMap::Metric m (session->tempo_map().metric_at (pos)); + TempoMetric m (_session->tempo_map().metric_at (pos)); sprintf (buf, "%-5.2f", m.tempo().beats_per_minute()); - if (bbt_lower_info_label->get_text() != buf) { - bbt_lower_info_label->set_text (buf); - } + supplemental_left->set_text (_text_cells[LowerLeft2], buf); + sprintf (buf, "%g|%g", m.meter().beats_per_bar(), m.meter().note_divisor()); - if (bbt_upper_info_label->get_text() != buf) { - bbt_upper_info_label->set_text (buf); - } + supplemental_right->set_text (_text_cells[LowerRight2], buf); } } void AudioClock::set_session (Session *s) { - session = s; + SessionHandlePtr::set_session (s); + + if (_session) { - if (s) { + _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&AudioClock::session_configuration_changed, this, _1), gui_context()); - XMLProperty* prop; - XMLNode* node = session->extra_xml (X_("ClockModes")); + const XMLProperty* prop; + XMLNode* node = _session->extra_xml (X_("ClockModes")); AudioClock::Mode amode; - + if (node) { - if ((prop = node->property (_name)) != 0) { - amode = AudioClock::Mode (string_2_enum (prop->value(), amode)); - set_mode (amode); + for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) { + if ((prop = (*i)->property (X_("name"))) && prop->value() == _name) { + + if ((prop = (*i)->property (X_("mode"))) != 0) { + amode = AudioClock::Mode (string_2_enum (prop->value(), amode)); + set_mode (amode); + } + if ((prop = (*i)->property (X_("on"))) != 0) { + set_off (!string_is_affirmative (prop->value())); + } + break; + } } } @@ -709,86 +675,131 @@ AudioClock::set_session (Session *s) } void -AudioClock::focus () +AudioClock::edit_next_field () { - switch (_mode) { - case SMPTE: - hours_ebox.grab_focus (); - break; - - case BBT: - bars_ebox.grab_focus (); - break; - - case MinSec: - ms_hours_ebox.grab_focus (); - break; - - case Frames: - frames_ebox.grab_focus (); - break; - - case Off: - break; - } -} - - -bool -AudioClock::field_key_press_event (GdkEventKey *ev, Field field) -{ - /* all key activity is handled on key release */ - return true; -} - -bool -AudioClock::field_key_release_event (GdkEventKey *ev, Field field) -{ - Label *label = 0; - string new_text; - char new_char = 0; - bool move_on = false; - - switch (field) { - case SMPTE_Hours: - label = &hours_label; - break; - case SMPTE_Minutes: - label = &minutes_label; + /* move on to the next field. + */ + + switch (editing_field) { + + /* Timecode */ + + case Timecode_Hours: + editing_field = Timecode_Minutes; + display->start_editing (_text_cells[Timecode_Minutes]); break; - case SMPTE_Seconds: - label = &seconds_label; + case Timecode_Minutes: + editing_field = Timecode_Seconds; + display->start_editing (_text_cells[Timecode_Seconds]); break; - case SMPTE_Frames: - label = &frames_label; + case Timecode_Seconds: + editing_field = Timecode_Frames; + display->start_editing (_text_cells[Timecode_Frames]); break; - - case AudioFrames: - label = &audio_frames_label; + case Timecode_Frames: + end_edit (); break; - + + /* Min:Sec */ + case MS_Hours: - label = &ms_hours_label; + editing_field = MS_Minutes; + display->start_editing (_text_cells[MS_Minutes]); break; case MS_Minutes: - label = &ms_minutes_label; + editing_field = MS_Seconds; + display->start_editing (_text_cells[MS_Seconds]); break; case MS_Seconds: - label = &ms_seconds_label; + editing_field = MS_Milliseconds; + display->start_editing (_text_cells[MS_Milliseconds]); break; - + case MS_Milliseconds: + end_edit (); + break; + + /* BBT */ + case Bars: - label = &bars_label; + editing_field = Beats; + display->start_editing (_text_cells[Beats]); break; case Beats: - label = &beats_label; + editing_field = Ticks; + display->start_editing (_text_cells[Ticks]); break; case Ticks: - label = &ticks_label; + end_edit (); + break; + + /* audio frames */ + case AudioFrames: + end_edit (); + break; + + default: break; + } + + key_entry_state = 0; +} + +bool +AudioClock::on_key_press_event (GdkEventKey* ev) +{ + /* return true for keys that we MIGHT use + at release + */ + switch (ev->keyval) { + case GDK_0: + case GDK_KP_0: + case GDK_1: + case GDK_KP_1: + case GDK_2: + case GDK_KP_2: + case GDK_3: + case GDK_KP_3: + case GDK_4: + case GDK_KP_4: + case GDK_5: + case GDK_KP_5: + case GDK_6: + case GDK_KP_6: + case GDK_7: + case GDK_KP_7: + case GDK_8: + case GDK_KP_8: + case GDK_9: + case GDK_KP_9: + case GDK_period: + case GDK_comma: + case GDK_KP_Decimal: + case GDK_Tab: + case GDK_Return: + case GDK_KP_Enter: + case GDK_Escape: + return true; default: return false; } +} + +bool +AudioClock::on_key_release_event (GdkEventKey *ev) +{ + if (editing_field == 0) { + return false; + } + + CairoTextCell *cell = _text_cells[editing_field]; + + if (!cell) { + return false; + } + + string new_text; + char new_char = 0; + bool move_on = false; switch (ev->keyval) { case GDK_0: @@ -833,9 +844,10 @@ AudioClock::field_key_release_event (GdkEventKey *ev, Field field) break; case GDK_period: + case GDK_comma: case GDK_KP_Decimal: - if (_mode == MinSec && field == MS_Seconds) { - new_char = '.'; + if (_mode == MinSec && editing_field == MS_Seconds) { + new_char = '.'; // XXX i18n } else { return false; } @@ -848,8 +860,7 @@ AudioClock::field_key_release_event (GdkEventKey *ev, Field field) break; case GDK_Escape: - key_entry_state = 0; - clock_base.grab_focus (); + end_edit (); ChangeAborted(); /* EMIT SIGNAL */ return true; @@ -863,8 +874,8 @@ AudioClock::field_key_release_event (GdkEventKey *ev, Field field) /* initialize with a fresh new string */ - if (field != AudioFrames) { - for (uint32_t xn = 0; xn < field_length[field] - 1; ++xn) { + if (editing_field != AudioFrames) { + for (uint32_t xn = 0; xn < field_length[editing_field] - 1; ++xn) { new_text += '0'; } } else { @@ -873,308 +884,121 @@ AudioClock::field_key_release_event (GdkEventKey *ev, Field field) } else { - string existing = label->get_text(); - if (existing.length() >= field_length[field]) { - new_text = existing.substr (1, field_length[field] - 1); + string existing = cell->get_text(); + if (existing.length() >= field_length[editing_field]) { + new_text = existing.substr (1, field_length[editing_field] - 1); } else { - new_text = existing.substr (0, field_length[field] - 1); + new_text = existing.substr (0, field_length[editing_field] - 1); } } new_text += new_char; - label->set_text (new_text); + display->set_text (cell, new_text); + _canonical_time_is_displayed = true; key_entry_state++; } - if (key_entry_state == field_length[field]) { + if (key_entry_state == field_length[editing_field]) { move_on = true; } - + if (move_on) { if (key_entry_state) { - - switch (field) { - case SMPTE_Hours: - case SMPTE_Minutes: - case SMPTE_Seconds: - case SMPTE_Frames: - // Check SMPTE fields for sanity (may also adjust fields) - smpte_sanitize_display(); + + /* if key_entry_state != then we edited the text + */ + + char buf[16]; + + switch (editing_field) { + case Timecode_Hours: + case Timecode_Minutes: + case Timecode_Seconds: + case Timecode_Frames: + // Check Timecode fields for sanity (may also adjust fields) + timecode_sanitize_display(); break; case Bars: case Beats: case Ticks: - // Bars should never be, unless this clock is for a duration - if (atoi(bars_label.get_text()) == 0 && !is_duration) { - bars_label.set_text("001"); + // Bars should never be zero, unless this clock is for a duration + if (atoi (_text_cells[Bars]->get_text()) == 0 && !is_duration) { + snprintf (buf, sizeof (buf), "%0*" PRIu32, field_length[Bars], 1); + display->set_text (_text_cells[Bars], buf); + _canonical_time_is_displayed = true; } - // beats should never be 0, unless this clock is for a duration - if (atoi(beats_label.get_text()) == 0 && !is_duration) { - beats_label.set_text("01"); + // beats should never be zero, unless this clock is for a duration + if (atoi (_text_cells[Beats]->get_text()) == 0 && !is_duration) { + snprintf (buf, sizeof (buf), "%0*" PRIu32, field_length[Beats], 1); + display->set_text (_text_cells[Beats], buf); + _canonical_time_is_displayed = true; } break; default: break; - } - - ValueChanged(); /* EMIT_SIGNAL */ - } - - /* move on to the next field. - */ - - switch (field) { - - /* SMPTE */ - - case SMPTE_Hours: - minutes_ebox.grab_focus (); - break; - case SMPTE_Minutes: - seconds_ebox.grab_focus (); - break; - case SMPTE_Seconds: - frames_ebox.grab_focus (); - break; - case SMPTE_Frames: - clock_base.grab_focus (); - break; - - /* audio frames */ - case AudioFrames: - clock_base.grab_focus (); - break; - - /* Min:Sec */ - - case MS_Hours: - ms_minutes_ebox.grab_focus (); - break; - case MS_Minutes: - ms_seconds_ebox.grab_focus (); - break; - case MS_Seconds: - clock_base.grab_focus (); - break; - - /* BBT */ - - case Bars: - beats_ebox.grab_focus (); - break; - case Beats: - ticks_ebox.grab_focus (); - break; - case Ticks: - clock_base.grab_focus (); - break; - - default: - break; - } - - } - - //if user hit Enter, lose focus - switch (ev->keyval) { - case GDK_Return: - case GDK_KP_Enter: - clock_base.grab_focus (); - } - - return true; -} - -bool -AudioClock::field_focus_in_event (GdkEventFocus *ev, Field field) -{ - key_entry_state = 0; - - Keyboard::magic_widget_grab_focus (); - - switch (field) { - case SMPTE_Hours: - hours_ebox.set_flags (Gtk::HAS_FOCUS); - hours_ebox.set_state (Gtk::STATE_ACTIVE); - break; - case SMPTE_Minutes: - minutes_ebox.set_flags (Gtk::HAS_FOCUS); - minutes_ebox.set_state (Gtk::STATE_ACTIVE); - break; - case SMPTE_Seconds: - seconds_ebox.set_flags (Gtk::HAS_FOCUS); - seconds_ebox.set_state (Gtk::STATE_ACTIVE); - break; - case SMPTE_Frames: - frames_ebox.set_flags (Gtk::HAS_FOCUS); - frames_ebox.set_state (Gtk::STATE_ACTIVE); - break; - - case AudioFrames: - audio_frames_ebox.set_flags (Gtk::HAS_FOCUS); - audio_frames_ebox.set_state (Gtk::STATE_ACTIVE); - break; - - case MS_Hours: - ms_hours_ebox.set_flags (Gtk::HAS_FOCUS); - ms_hours_ebox.set_state (Gtk::STATE_ACTIVE); - break; - case MS_Minutes: - ms_minutes_ebox.set_flags (Gtk::HAS_FOCUS); - ms_minutes_ebox.set_state (Gtk::STATE_ACTIVE); - break; - case MS_Seconds: - ms_seconds_ebox.set_flags (Gtk::HAS_FOCUS); - ms_seconds_ebox.set_state (Gtk::STATE_ACTIVE); - break; - case Bars: - bars_ebox.set_flags (Gtk::HAS_FOCUS); - bars_ebox.set_state (Gtk::STATE_ACTIVE); - break; - case Beats: - beats_ebox.set_flags (Gtk::HAS_FOCUS); - beats_ebox.set_state (Gtk::STATE_ACTIVE); - break; - case Ticks: - ticks_ebox.set_flags (Gtk::HAS_FOCUS); - ticks_ebox.set_state (Gtk::STATE_ACTIVE); - break; - } - - return false; -} - -bool -AudioClock::field_focus_out_event (GdkEventFocus *ev, Field field) -{ - switch (field) { - - case SMPTE_Hours: - hours_ebox.unset_flags (Gtk::HAS_FOCUS); - hours_ebox.set_state (Gtk::STATE_NORMAL); - break; - case SMPTE_Minutes: - minutes_ebox.unset_flags (Gtk::HAS_FOCUS); - minutes_ebox.set_state (Gtk::STATE_NORMAL); - break; - case SMPTE_Seconds: - seconds_ebox.unset_flags (Gtk::HAS_FOCUS); - seconds_ebox.set_state (Gtk::STATE_NORMAL); - break; - case SMPTE_Frames: - frames_ebox.unset_flags (Gtk::HAS_FOCUS); - frames_ebox.set_state (Gtk::STATE_NORMAL); - break; - - case AudioFrames: - audio_frames_ebox.unset_flags (Gtk::HAS_FOCUS); - audio_frames_ebox.set_state (Gtk::STATE_NORMAL); - break; - - case MS_Hours: - ms_hours_ebox.unset_flags (Gtk::HAS_FOCUS); - ms_hours_ebox.set_state (Gtk::STATE_NORMAL); - break; - case MS_Minutes: - ms_minutes_ebox.unset_flags (Gtk::HAS_FOCUS); - ms_minutes_ebox.set_state (Gtk::STATE_NORMAL); - break; - case MS_Seconds: - ms_seconds_ebox.unset_flags (Gtk::HAS_FOCUS); - ms_seconds_ebox.set_state (Gtk::STATE_NORMAL); - break; - - case Bars: - bars_ebox.unset_flags (Gtk::HAS_FOCUS); - bars_ebox.set_state (Gtk::STATE_NORMAL); - break; - case Beats: - beats_ebox.unset_flags (Gtk::HAS_FOCUS); - beats_ebox.set_state (Gtk::STATE_NORMAL); - break; - case Ticks: - ticks_ebox.unset_flags (Gtk::HAS_FOCUS); - ticks_ebox.set_state (Gtk::STATE_NORMAL); - break; - } - - Keyboard::magic_widget_drop_focus (); - - return false; -} + } -bool -AudioClock::field_button_release_event (GdkEventButton *ev, Field field) -{ - if (dragging) { - gdk_pointer_ungrab (GDK_CURRENT_TIME); - dragging = false; - if (ev->y > drag_start_y+1 || ev->y < drag_start_y-1 || Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)){ - // we actually dragged so return without setting editing focus, or we shift clicked - return true; + ValueChanged(); /* EMIT_SIGNAL */ } + + edit_next_field (); } - if (!editable) { - if (ops_menu == 0) { - build_ops_menu (); - } - ops_menu->popup (1, ev->time); - return true; + //if user hit Enter, lose focus + switch (ev->keyval) { + case GDK_Return: + case GDK_KP_Enter: + end_edit (); } - if (Keyboard::is_context_menu_event (ev)) { - if (ops_menu == 0) { - build_ops_menu (); - } - ops_menu->popup (1, ev->time); - return true; - } + return true; +} +bool +AudioClock::button_press (GdkEventButton *ev, CairoCell* cell) +{ switch (ev->button) { case 1: - switch (field) { - case SMPTE_Hours: - hours_ebox.grab_focus(); - break; - case SMPTE_Minutes: - minutes_ebox.grab_focus(); - break; - case SMPTE_Seconds: - seconds_ebox.grab_focus(); - break; - case SMPTE_Frames: - frames_ebox.grab_focus(); - break; - - case AudioFrames: - audio_frames_ebox.grab_focus(); - break; + if (editable) { + if (cell) { + Field f = (Field) cell->id (); + switch (f) { + case Timecode_Hours: + case Timecode_Minutes: + case Timecode_Seconds: + case Timecode_Frames: + case MS_Hours: + case MS_Minutes: + case MS_Seconds: + case MS_Milliseconds: + case Bars: + case Beats: + case Ticks: + case AudioFrames: + editing_field = f; + display->start_editing (cell); + break; + default: + return false; + } + } - case MS_Hours: - ms_hours_ebox.grab_focus(); - break; - case MS_Minutes: - ms_minutes_ebox.grab_focus(); - break; - case MS_Seconds: - ms_seconds_ebox.grab_focus(); - break; + Keyboard::magic_widget_grab_focus (); - case Bars: - bars_ebox.grab_focus (); - break; - case Beats: - beats_ebox.grab_focus (); - break; - case Ticks: - ticks_ebox.grab_focus (); - break; + /* make absolutely sure that the pointer is grabbed */ + gdk_pointer_grab(ev->window,false , + GdkEventMask( Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK |Gdk::BUTTON_RELEASE_MASK), + NULL,NULL,ev->time); + dragging = true; + drag_accum = 0; + drag_start_y = ev->y; + drag_y = ev->y; } break; default: + return false; break; } @@ -1182,88 +1006,90 @@ AudioClock::field_button_release_event (GdkEventButton *ev, Field field) } bool -AudioClock::field_button_press_event (GdkEventButton *ev, Field field) +AudioClock::button_release (GdkEventButton *ev, CairoCell*) { - if (session == 0) return false; - - nframes_t frames = 0; - - switch (ev->button) { - case 1: - if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) { - set (frames, true); - ValueChanged (); /* EMIT_SIGNAL */ - } - - /* make absolutely sure that the pointer is grabbed */ - gdk_pointer_grab(ev->window,false , - GdkEventMask( Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK |Gdk::BUTTON_RELEASE_MASK), - NULL,NULL,ev->time); - dragging = true; - drag_accum = 0; - drag_start_y = ev->y; - drag_y = ev->y; - break; - - case 2: - if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) { - set (frames, true); - ValueChanged (); /* EMIT_SIGNAL */ + if (editable) { + if (dragging) { + gdk_pointer_ungrab (GDK_CURRENT_TIME); + dragging = false; + if (ev->y > drag_start_y+1 || ev->y < drag_start_y-1 || Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)){ + // we actually dragged so return without setting editing focus, or we shift clicked + return true; + } } - break; - - case 3: - /* used for context sensitive menu */ - return false; - break; + } - default: - return false; - break; + if (Keyboard::is_context_menu_event (ev)) { + if (ops_menu == 0) { + build_ops_menu (); + } + ops_menu->popup (1, ev->time); + return true; } - - return true; + + return false; } bool -AudioClock::field_button_scroll_event (GdkEventScroll *ev, Field field) +AudioClock::scroll (GdkEventScroll *ev, CairoCell* cell) { - if (session == 0) { + if (_session == 0 || !editable) { return false; } - nframes_t frames = 0; + if (cell) { + Field f = (Field) cell->id (); + switch (f) { + case Timecode_Hours: + case Timecode_Minutes: + case Timecode_Seconds: + case Timecode_Frames: + case MS_Hours: + case MS_Minutes: + case MS_Seconds: + case MS_Milliseconds: + case Bars: + case Beats: + case Ticks: + case AudioFrames: + break; + default: + return false; + } + } + + framepos_t frames = 0; switch (ev->direction) { case GDK_SCROLL_UP: - frames = get_frames (field); - if (frames != 0) { - if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) { - frames *= 10; - } - set (current_time() + frames, true); - ValueChanged (); /* EMIT_SIGNAL */ - } - break; - + frames = get_frames ((Field) cell->id()); + if (frames != 0) { + if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) { + frames *= 10; + } + set (current_time() + frames, true); + ValueChanged (); /* EMIT_SIGNAL */ + } + break; + case GDK_SCROLL_DOWN: - frames = get_frames (field); - if (frames != 0) { - if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) { - frames *= 10; - } - - if ((double)current_time() - (double)frames < 0.0) { - set (0, true); - } else { - set (current_time() - frames, true); - } - - ValueChanged (); /* EMIT_SIGNAL */ - } - break; - + frames = get_frames ((Field) cell->id()); + if (frames != 0) { + if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) { + frames *= 10; + } + + if ((double)current_time() - (double)frames < 0.0) { + set (0, true); + } else { + set (current_time() - frames, true); + } + + ValueChanged (); /* EMIT_SIGNAL */ + } + break; + default: return false; break; @@ -1275,10 +1101,10 @@ AudioClock::field_button_scroll_event (GdkEventScroll *ev, Field field) bool AudioClock::field_motion_notify_event (GdkEventMotion *ev, Field field) { - if (session == 0 || !dragging) { + if (_session == 0 || !dragging) { return false; } - + float pixel_frame_scale_factor = 0.2f; /* @@ -1287,7 +1113,7 @@ AudioClock::field_motion_notify_event (GdkEventMotion *ev, Field field) } - if (Keyboard::modifier_state_contains (ev->state, + if (Keyboard::modifier_state_contains (ev->state, Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)) { pixel_frame_scale_factor = 0.025f; @@ -1301,96 +1127,106 @@ AudioClock::field_motion_notify_event (GdkEventMotion *ev, Field field) if (trunc(drag_accum) != 0) { - nframes_t frames; - nframes_t pos ; + framepos_t frames; + framepos_t pos; int dir; dir = (drag_accum < 0 ? 1:-1); pos = current_time(); frames = get_frames (field,pos,dir); - + if (frames != 0 && frames * drag_accum < current_time()) { - - set ((nframes_t) floor (pos - drag_accum * frames), false); // minus because up is negative in computer-land - + + set ((framepos_t) floor (pos - drag_accum * frames), false); // minus because up is negative in computer-land + } else { set (0 , false); - + } drag_accum= 0; - ValueChanged(); /* EMIT_SIGNAL */ - + ValueChanged(); /* EMIT_SIGNAL */ + } return true; } -nframes_t -AudioClock::get_frames (Field field,nframes_t pos,int dir) +framepos_t +AudioClock::get_frames (Field field, framepos_t pos, int dir) { - - nframes_t frames = 0; - BBT_Time bbt; + framecnt_t f = 0; + Timecode::BBT_Time BBT; switch (field) { - case SMPTE_Hours: - frames = (nframes_t) floor (3600.0 * session->frame_rate()); + case Timecode_Hours: + f = (framecnt_t) floor (3600.0 * _session->frame_rate()); break; - case SMPTE_Minutes: - frames = (nframes_t) floor (60.0 * session->frame_rate()); + case Timecode_Minutes: + f = (framecnt_t) floor (60.0 * _session->frame_rate()); break; - case SMPTE_Seconds: - frames = session->frame_rate(); + case Timecode_Seconds: + f = _session->frame_rate(); break; - case SMPTE_Frames: - frames = (nframes_t) floor (session->frame_rate() / session->smpte_frames_per_second()); + case Timecode_Frames: + f = (framecnt_t) floor (_session->frame_rate() / _session->timecode_frames_per_second()); break; case AudioFrames: - frames = 1; + f = 1; break; case MS_Hours: - frames = (nframes_t) floor (3600.0 * session->frame_rate()); + f = (framecnt_t) floor (3600.0 * _session->frame_rate()); break; case MS_Minutes: - frames = (nframes_t) floor (60.0 * session->frame_rate()); + f = (framecnt_t) floor (60.0 * _session->frame_rate()); break; case MS_Seconds: - frames = session->frame_rate(); + f = (framecnt_t) _session->frame_rate(); + break; + case MS_Milliseconds: + f = (framecnt_t) floor (_session->frame_rate() / 1000.0); break; case Bars: - bbt.bars = 1; - bbt.beats = 0; - bbt.ticks = 0; - frames = session->tempo_map().bbt_duration_at(pos,bbt,dir); + BBT.bars = 1; + BBT.beats = 0; + BBT.ticks = 0; + f = _session->tempo_map().bbt_duration_at (pos,BBT,dir); break; case Beats: - bbt.bars = 0; - bbt.beats = 1; - bbt.ticks = 0; - frames = session->tempo_map().bbt_duration_at(pos,bbt,dir); + BBT.bars = 0; + BBT.beats = 1; + BBT.ticks = 0; + f = _session->tempo_map().bbt_duration_at(pos,BBT,dir); break; case Ticks: - bbt.bars = 0; - bbt.beats = 0; - bbt.ticks = 1; - frames = session->tempo_map().bbt_duration_at(pos,bbt,dir); + BBT.bars = 0; + BBT.beats = 0; + BBT.ticks = 1; + f = _session->tempo_map().bbt_duration_at(pos,BBT,dir); + break; + default: + error << string_compose (_("programming error: %1"), "attempt to get frames from non-text field!") << endmsg; + f = 0; break; } - return frames; + return f; } -nframes_t -AudioClock::current_time (nframes_t pos) const +framepos_t +AudioClock::current_time (framepos_t pos) const { - nframes_t ret = 0; + if (!_canonical_time_is_displayed) { + return _canonical_time; + } + + framepos_t ret = 0; switch (_mode) { - case SMPTE: - ret = smpte_frame_from_display (); + case Timecode: + ret = timecode_frame_from_display (); break; case BBT: ret = bbt_frame_from_display (pos); @@ -1403,22 +1239,19 @@ AudioClock::current_time (nframes_t pos) const case Frames: ret = audio_frame_from_display (); break; - - case Off: - break; } return ret; } -nframes_t -AudioClock::current_duration (nframes_t pos) const +framepos_t +AudioClock::current_duration (framepos_t pos) const { - nframes_t ret = 0; + framepos_t ret = 0; switch (_mode) { - case SMPTE: - ret = smpte_frame_from_display (); + case Timecode: + ret = timecode_frame_from_display (); break; case BBT: ret = bbt_frame_duration_from_display (pos); @@ -1431,466 +1264,488 @@ AudioClock::current_duration (nframes_t pos) const case Frames: ret = audio_frame_from_display (); break; - - case Off: - break; } return ret; } void -AudioClock::smpte_sanitize_display() +AudioClock::timecode_sanitize_display() { - // Check SMPTE fields for sanity, possibly adjusting values - if (atoi(minutes_label.get_text()) > 59) { - minutes_label.set_text("59"); + // Check Timecode fields for sanity, possibly adjusting values + if (atoi (_text_cells[Timecode_Minutes]->get_text()) > 59) { + display->set_text (_text_cells[Timecode_Minutes], "59"); + _canonical_time_is_displayed = true; } - - if (atoi(seconds_label.get_text()) > 59) { - seconds_label.set_text("59"); + + if (atoi (_text_cells[Timecode_Seconds]->get_text()) > 59) { + display->set_text (_text_cells[Timecode_Seconds], "59"); + _canonical_time_is_displayed = true; } - - switch ((long)rint(session->smpte_frames_per_second())) { + + switch ((long)rint(_session->timecode_frames_per_second())) { case 24: - if (atoi(frames_label.get_text()) > 23) { - frames_label.set_text("23"); + if (atoi (_text_cells[Timecode_Frames]->get_text()) > 23) { + display->set_text (_text_cells[Timecode_Frames], "23"); + _canonical_time_is_displayed = true; } break; case 25: - if (atoi(frames_label.get_text()) > 24) { - frames_label.set_text("24"); + if (atoi (_text_cells[Timecode_Frames]->get_text()) > 24) { + display->set_text (_text_cells[Timecode_Frames], "24"); + _canonical_time_is_displayed = true; } break; case 30: - if (atoi(frames_label.get_text()) > 29) { - frames_label.set_text("29"); + if (atoi (_text_cells[Timecode_Frames]->get_text()) > 29) { + display->set_text (_text_cells[Timecode_Frames], "29"); + _canonical_time_is_displayed = true; } break; default: break; } - - if (session->smpte_drop_frames()) { - if ((atoi(minutes_label.get_text()) % 10) && (atoi(seconds_label.get_text()) == 0) && (atoi(frames_label.get_text()) < 2)) { - frames_label.set_text("02"); + + if (_session->timecode_drop_frames()) { + if ((atoi (_text_cells[Timecode_Minutes]->get_text()) % 10) && (atoi (_text_cells[Timecode_Seconds]->get_text()) == 0) && (atoi (_text_cells[Timecode_Frames]->get_text()) < 2)) { + display->set_text (_text_cells[Timecode_Frames], "02"); + _canonical_time_is_displayed = true; } } } -nframes_t -AudioClock::smpte_frame_from_display () const +/** This is necessary because operator[] isn't const with std::map. + * @param f Field. + * @return Label widget. + */ +CairoTextCell* +AudioClock::label (Field f) const +{ + std::map::const_iterator i = _text_cells.find (f); + assert (i != _text_cells.end ()); + + return i->second; +} + +framepos_t +AudioClock::timecode_frame_from_display () const { - if (session == 0) { + if (_session == 0) { return 0; } - - SMPTE::Time smpte; - nframes_t sample; - - smpte.hours = atoi (hours_label.get_text()); - smpte.minutes = atoi (minutes_label.get_text()); - smpte.seconds = atoi (seconds_label.get_text()); - smpte.frames = atoi (frames_label.get_text()); - smpte.rate = session->smpte_frames_per_second(); - smpte.drop= session->smpte_drop_frames(); - - session->smpte_to_sample( smpte, sample, false /* use_offset */, false /* use_subframes */ ); - + + Timecode::Time TC; + framepos_t sample; + + if (!label (Timecode_Sign)->get_text().empty()) { + TC.hours = atoi (label (Timecode_Hours)->get_text()); + } else { + TC.hours = -atoi (label (Timecode_Hours)->get_text()); + } + + TC.minutes = atoi (label (Timecode_Minutes)->get_text()); + TC.seconds = atoi (label (Timecode_Seconds)->get_text()); + TC.frames = atoi (label (Timecode_Frames)->get_text()); + TC.rate = _session->timecode_frames_per_second(); + TC.drop= _session->timecode_drop_frames(); + + _session->timecode_to_sample (TC, sample, false /* use_offset */, false /* use_subframes */ ); + #if 0 -#define SMPTE_SAMPLE_TEST_1 -#define SMPTE_SAMPLE_TEST_2 -#define SMPTE_SAMPLE_TEST_3 -#define SMPTE_SAMPLE_TEST_4 -#define SMPTE_SAMPLE_TEST_5 -#define SMPTE_SAMPLE_TEST_6 -#define SMPTE_SAMPLE_TEST_7 - - // Testcode for smpte<->sample conversions (P.S.) - SMPTE::Time smpte1; - nframes_t sample1; - nframes_t oldsample = 0; - SMPTE::Time smpte2; - nframes_t sample_increment; - - sample_increment = (long)rint(session->frame_rate() / session->smpte_frames_per_second); - -#ifdef SMPTE_SAMPLE_TEST_1 +#define Timecode_SAMPLE_TEST_1 +#define Timecode_SAMPLE_TEST_2 +#define Timecode_SAMPLE_TEST_3 +#define Timecode_SAMPLE_TEST_4 +#define Timecode_SAMPLE_TEST_5 +#define Timecode_SAMPLE_TEST_6 +#define Timecode_SAMPLE_TEST_7 + + // Testcode for timecode<->sample conversions (P.S.) + Timecode::Time timecode1; + framepos_t sample1; + framepos_t oldsample = 0; + Timecode::Time timecode2; + framecnt_t sample_increment; + + sample_increment = (framecnt_t)rint(_session->frame_rate() / _session->timecode_frames_per_second); + +#ifdef Timecode_SAMPLE_TEST_1 // Test 1: use_offset = false, use_subframes = false cout << "use_offset = false, use_subframes = false" << endl; for (int i = 0; i < 108003; i++) { - session->smpte_to_sample( smpte1, sample1, false /* use_offset */, false /* use_subframes */ ); - session->sample_to_smpte( sample1, smpte2, false /* use_offset */, false /* use_subframes */ ); + _session->timecode_to_sample( timecode1, sample1, false /* use_offset */, false /* use_subframes */ ); + _session->sample_to_timecode( sample1, timecode2, false /* use_offset */, false /* use_subframes */ ); if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) { cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl; - cout << "smpte1: " << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> "; + cout << "timecode1: " << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; cout << "sample: " << sample1 << endl; cout << "sample: " << sample1 << " -> "; - cout << "smpte2: " << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; + cout << "timecode2: " << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; break; } - - if (smpte2.hours != smpte1.hours || smpte2.minutes != smpte1.minutes || smpte2.seconds != smpte2.seconds || smpte2.frames != smpte1.frames) { - cout << "ERROR: smpte2 not equal smpte1" << endl; - cout << "smpte1: " << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> "; + + if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) { + cout << "ERROR: timecode2 not equal timecode1" << endl; + cout << "timecode1: " << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; cout << "sample: " << sample1 << endl; cout << "sample: " << sample1 << " -> "; - cout << "smpte2: " << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; + cout << "timecode2: " << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; break; } oldsample = sample1; - session->smpte_increment( smpte1 ); + _session->timecode_increment( timecode1 ); } cout << "sample_increment: " << sample_increment << endl; cout << "sample: " << sample1 << " -> "; - cout << "smpte: " << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; + cout << "timecode: " << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; #endif -#ifdef SMPTE_SAMPLE_TEST_2 +#ifdef Timecode_SAMPLE_TEST_2 // Test 2: use_offset = true, use_subframes = false cout << "use_offset = true, use_subframes = false" << endl; - - smpte1.hours = 0; - smpte1.minutes = 0; - smpte1.seconds = 0; - smpte1.frames = 0; - smpte1.subframes = 0; + + timecode1.hours = 0; + timecode1.minutes = 0; + timecode1.seconds = 0; + timecode1.frames = 0; + timecode1.subframes = 0; sample1 = oldsample = 0; - session->sample_to_smpte( sample1, smpte1, true /* use_offset */, false /* use_subframes */ ); + _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ ); cout << "Starting at sample: " << sample1 << " -> "; - cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << endl; + cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl; for (int i = 0; i < 108003; i++) { - session->smpte_to_sample( smpte1, sample1, true /* use_offset */, false /* use_subframes */ ); - session->sample_to_smpte( sample1, smpte2, true /* use_offset */, false /* use_subframes */ ); + _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ ); + _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ ); -// cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> "; +// cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; // cout << "sample: " << sample1 << endl; // cout << "sample: " << sample1 << " -> "; -// cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; - +// cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; + if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) { cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl; - cout << "smpte1: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> "; + cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; cout << "sample: " << sample1 << endl; cout << "sample: " << sample1 << " -> "; - cout << "smpte2: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; + cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; break; } - - if (smpte2.hours != smpte1.hours || smpte2.minutes != smpte1.minutes || smpte2.seconds != smpte2.seconds || smpte2.frames != smpte1.frames) { - cout << "ERROR: smpte2 not equal smpte1" << endl; - cout << "smpte1: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> "; + + if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) { + cout << "ERROR: timecode2 not equal timecode1" << endl; + cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; cout << "sample: " << sample1 << endl; cout << "sample: " << sample1 << " -> "; - cout << "smpte2: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; + cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; break; } oldsample = sample1; - session->smpte_increment( smpte1 ); + _session->timecode_increment( timecode1 ); } cout << "sample_increment: " << sample_increment << endl; cout << "sample: " << sample1 << " -> "; - cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; + cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; #endif -#ifdef SMPTE_SAMPLE_TEST_3 +#ifdef Timecode_SAMPLE_TEST_3 // Test 3: use_offset = true, use_subframes = false, decrement - cout << "use_offset = true, use_subframes = false, decrement" << endl; + cout << "use_offset = true, use_subframes = false, decrement" << endl; - session->sample_to_smpte( sample1, smpte1, true /* use_offset */, false /* use_subframes */ ); + _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ ); cout << "Starting at sample: " << sample1 << " -> "; - cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << endl; + cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl; for (int i = 0; i < 108003; i++) { - session->smpte_to_sample( smpte1, sample1, true /* use_offset */, false /* use_subframes */ ); - session->sample_to_smpte( sample1, smpte2, true /* use_offset */, false /* use_subframes */ ); + _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ ); + _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ ); -// cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> "; +// cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; // cout << "sample: " << sample1 << endl; // cout << "sample: " << sample1 << " -> "; -// cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; - +// cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; + if ((i > 0) && ( ((oldsample - sample1) != sample_increment) && ((oldsample - sample1) != (sample_increment + 1)) && ((oldsample - sample1) != (sample_increment - 1)))) { cout << "ERROR: sample increment not right: " << (oldsample - sample1) << " != " << sample_increment << endl; - cout << "smpte1: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> "; + cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; cout << "sample: " << sample1 << endl; cout << "sample: " << sample1 << " -> "; - cout << "smpte2: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; + cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; break; } - - if (smpte2.hours != smpte1.hours || smpte2.minutes != smpte1.minutes || smpte2.seconds != smpte2.seconds || smpte2.frames != smpte1.frames) { - cout << "ERROR: smpte2 not equal smpte1" << endl; - cout << "smpte1: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> "; + + if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) { + cout << "ERROR: timecode2 not equal timecode1" << endl; + cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; cout << "sample: " << sample1 << endl; cout << "sample: " << sample1 << " -> "; - cout << "smpte2: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; + cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; break; } oldsample = sample1; - session->smpte_decrement( smpte1 ); + _session->timecode_decrement( timecode1 ); } cout << "sample_decrement: " << sample_increment << endl; cout << "sample: " << sample1 << " -> "; - cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; + cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; #endif -#ifdef SMPTE_SAMPLE_TEST_4 +#ifdef Timecode_SAMPLE_TEST_4 // Test 4: use_offset = true, use_subframes = true cout << "use_offset = true, use_subframes = true" << endl; - + for (long sub = 5; sub < 80; sub += 5) { - smpte1.hours = 0; - smpte1.minutes = 0; - smpte1.seconds = 0; - smpte1.frames = 0; - smpte1.subframes = 0; + timecode1.hours = 0; + timecode1.minutes = 0; + timecode1.seconds = 0; + timecode1.frames = 0; + timecode1.subframes = 0; sample1 = oldsample = (sample_increment * sub) / 80; - - session->sample_to_smpte( sample1, smpte1, true /* use_offset */, true /* use_subframes */ ); - + + _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, true /* use_subframes */ ); + cout << "starting at sample: " << sample1 << " -> "; - cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << endl; - + cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl; + for (int i = 0; i < 108003; i++) { - session->smpte_to_sample( smpte1, sample1, true /* use_offset */, true /* use_subframes */ ); - session->sample_to_smpte( sample1, smpte2, true /* use_offset */, true /* use_subframes */ ); - + _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, true /* use_subframes */ ); + _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, true /* use_subframes */ ); + if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) { cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl; - cout << "smpte1: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> "; + cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; cout << "sample: " << sample1 << endl; cout << "sample: " << sample1 << " -> "; - cout << "smpte2: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; + cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; //break; } - - if (smpte2.hours != smpte1.hours || smpte2.minutes != smpte1.minutes || smpte2.seconds != smpte2.seconds || smpte2.frames != smpte1.frames || smpte2.subframes != smpte1.subframes) { - cout << "ERROR: smpte2 not equal smpte1" << endl; - cout << "smpte1: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> "; + + if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames || timecode2.subframes != timecode1.subframes) { + cout << "ERROR: timecode2 not equal timecode1" << endl; + cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; cout << "sample: " << sample1 << endl; cout << "sample: " << sample1 << " -> "; - cout << "smpte2: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; + cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; break; } oldsample = sample1; - session->smpte_increment( smpte1 ); + _session->timecode_increment( timecode1 ); } - + cout << "sample_increment: " << sample_increment << endl; cout << "sample: " << sample1 << " -> "; - cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; + cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; for (int i = 0; i < 108003; i++) { - session->smpte_to_sample( smpte1, sample1, true /* use_offset */, true /* use_subframes */ ); - session->sample_to_smpte( sample1, smpte2, true /* use_offset */, true /* use_subframes */ ); - + _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, true /* use_subframes */ ); + _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, true /* use_subframes */ ); + if ((i > 0) && ( ((oldsample - sample1) != sample_increment) && ((oldsample - sample1) != (sample_increment + 1)) && ((oldsample - sample1) != (sample_increment - 1)))) { cout << "ERROR: sample increment not right: " << (oldsample - sample1) << " != " << sample_increment << endl; - cout << "smpte1: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> "; + cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; cout << "sample: " << sample1 << endl; cout << "sample: " << sample1 << " -> "; - cout << "smpte2: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; + cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; //break; } - - if (smpte2.hours != smpte1.hours || smpte2.minutes != smpte1.minutes || smpte2.seconds != smpte2.seconds || smpte2.frames != smpte1.frames || smpte2.subframes != smpte1.subframes) { - cout << "ERROR: smpte2 not equal smpte1" << endl; - cout << "smpte1: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> "; + + if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames || timecode2.subframes != timecode1.subframes) { + cout << "ERROR: timecode2 not equal timecode1" << endl; + cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; cout << "sample: " << sample1 << endl; cout << "sample: " << sample1 << " -> "; - cout << "smpte2: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; + cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; break; } oldsample = sample1; - session->smpte_decrement( smpte1 ); + _session->timecode_decrement( timecode1 ); } - + cout << "sample_decrement: " << sample_increment << endl; cout << "sample: " << sample1 << " -> "; - cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; + cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; } #endif -#ifdef SMPTE_SAMPLE_TEST_5 +#ifdef Timecode_SAMPLE_TEST_5 // Test 5: use_offset = true, use_subframes = false, increment seconds cout << "use_offset = true, use_subframes = false, increment seconds" << endl; - - smpte1.hours = 0; - smpte1.minutes = 0; - smpte1.seconds = 0; - smpte1.frames = 0; - smpte1.subframes = 0; + + timecode1.hours = 0; + timecode1.minutes = 0; + timecode1.seconds = 0; + timecode1.frames = 0; + timecode1.subframes = 0; sample1 = oldsample = 0; - sample_increment = session->frame_rate(); + sample_increment = _session->frame_rate(); - session->sample_to_smpte( sample1, smpte1, true /* use_offset */, false /* use_subframes */ ); + _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ ); cout << "Starting at sample: " << sample1 << " -> "; - cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << endl; + cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl; for (int i = 0; i < 3600; i++) { - session->smpte_to_sample( smpte1, sample1, true /* use_offset */, false /* use_subframes */ ); - session->sample_to_smpte( sample1, smpte2, true /* use_offset */, false /* use_subframes */ ); + _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ ); + _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ ); -// cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> "; +// cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; // cout << "sample: " << sample1 << endl; // cout << "sample: " << sample1 << " -> "; -// cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; - +// cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; + // if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) // { // cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl; // break; // } - - if (smpte2.hours != smpte1.hours || smpte2.minutes != smpte1.minutes || smpte2.seconds != smpte2.seconds || smpte2.frames != smpte1.frames) { - cout << "ERROR: smpte2 not equal smpte1" << endl; - cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> "; + + if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) { + cout << "ERROR: timecode2 not equal timecode1" << endl; + cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; cout << "sample: " << sample1 << endl; cout << "sample: " << sample1 << " -> "; - cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; + cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; break; } oldsample = sample1; - session->smpte_increment_seconds( smpte1 ); + _session->timecode_increment_seconds( timecode1 ); } cout << "sample_increment: " << sample_increment << endl; cout << "sample: " << sample1 << " -> "; - cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; + cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; #endif -#ifdef SMPTE_SAMPLE_TEST_6 +#ifdef Timecode_SAMPLE_TEST_6 // Test 6: use_offset = true, use_subframes = false, increment minutes cout << "use_offset = true, use_subframes = false, increment minutes" << endl; - - smpte1.hours = 0; - smpte1.minutes = 0; - smpte1.seconds = 0; - smpte1.frames = 0; - smpte1.subframes = 0; + + timecode1.hours = 0; + timecode1.minutes = 0; + timecode1.seconds = 0; + timecode1.frames = 0; + timecode1.subframes = 0; sample1 = oldsample = 0; - sample_increment = session->frame_rate() * 60; + sample_increment = _session->frame_rate() * 60; - session->sample_to_smpte( sample1, smpte1, true /* use_offset */, false /* use_subframes */ ); + _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ ); cout << "Starting at sample: " << sample1 << " -> "; - cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << endl; + cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl; for (int i = 0; i < 60; i++) { - session->smpte_to_sample( smpte1, sample1, true /* use_offset */, false /* use_subframes */ ); - session->sample_to_smpte( sample1, smpte2, true /* use_offset */, false /* use_subframes */ ); + _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ ); + _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ ); -// cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> "; +// cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; // cout << "sample: " << sample1 << endl; // cout << "sample: " << sample1 << " -> "; -// cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; - +// cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; + // if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) // { // cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl; // break; // } - - if (smpte2.hours != smpte1.hours || smpte2.minutes != smpte1.minutes || smpte2.seconds != smpte2.seconds || smpte2.frames != smpte1.frames) { - cout << "ERROR: smpte2 not equal smpte1" << endl; - cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> "; + + if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) { + cout << "ERROR: timecode2 not equal timecode1" << endl; + cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; cout << "sample: " << sample1 << endl; cout << "sample: " << sample1 << " -> "; - cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; + cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; break; } oldsample = sample1; - session->smpte_increment_minutes( smpte1 ); + _session->timecode_increment_minutes( timecode1 ); } cout << "sample_increment: " << sample_increment << endl; cout << "sample: " << sample1 << " -> "; - cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; + cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; #endif -#ifdef SMPTE_SAMPLE_TEST_7 +#ifdef Timecode_SAMPLE_TEST_7 // Test 7: use_offset = true, use_subframes = false, increment hours cout << "use_offset = true, use_subframes = false, increment hours" << endl; - - smpte1.hours = 0; - smpte1.minutes = 0; - smpte1.seconds = 0; - smpte1.frames = 0; - smpte1.subframes = 0; + + timecode1.hours = 0; + timecode1.minutes = 0; + timecode1.seconds = 0; + timecode1.frames = 0; + timecode1.subframes = 0; sample1 = oldsample = 0; - sample_increment = session->frame_rate() * 60 * 60; + sample_increment = _session->frame_rate() * 60 * 60; - session->sample_to_smpte( sample1, smpte1, true /* use_offset */, false /* use_subframes */ ); + _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ ); cout << "Starting at sample: " << sample1 << " -> "; - cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << endl; + cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl; for (int i = 0; i < 10; i++) { - session->smpte_to_sample( smpte1, sample1, true /* use_offset */, false /* use_subframes */ ); - session->sample_to_smpte( sample1, smpte2, true /* use_offset */, false /* use_subframes */ ); + _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ ); + _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ ); -// cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> "; +// cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; // cout << "sample: " << sample1 << endl; // cout << "sample: " << sample1 << " -> "; -// cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; - +// cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; + // if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) // { // cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl; // break; // } - - if (smpte2.hours != smpte1.hours || smpte2.minutes != smpte1.minutes || smpte2.seconds != smpte2.seconds || smpte2.frames != smpte1.frames) { - cout << "ERROR: smpte2 not equal smpte1" << endl; - cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> "; + + if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) { + cout << "ERROR: timecode2 not equal timecode1" << endl; + cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> "; cout << "sample: " << sample1 << endl; cout << "sample: " << sample1 << " -> "; - cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; + cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; break; } oldsample = sample1; - session->smpte_increment_hours( smpte1 ); + _session->timecode_increment_hours( timecode1 ); } cout << "sample_increment: " << sample_increment << endl; cout << "sample: " << sample1 << " -> "; - cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl; + cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl; #endif -#endif +#endif return sample; } -nframes_t +framepos_t AudioClock::minsec_frame_from_display () const { - if (session == 0) { + if (_session == 0) { return 0; } - int hrs = atoi (ms_hours_label.get_text()); - int mins = atoi (ms_minutes_label.get_text()); - float secs = atof (ms_seconds_label.get_text()); + int hrs = atoi (label (MS_Hours)->get_text()); + int mins = atoi (label (MS_Minutes)->get_text()); + int secs = atoi (label (MS_Seconds)->get_text()); + int millisecs = atoi (label (MS_Milliseconds)->get_text()); - nframes_t sr = session->frame_rate(); + framecnt_t sr = _session->frame_rate(); - return (nframes_t) floor ((hrs * 60.0f * 60.0f * sr) + (mins * 60.0f * sr) + (secs * sr)); + return (framepos_t) floor ((hrs * 60.0f * 60.0f * sr) + (mins * 60.0f * sr) + (secs * sr) + (millisecs * sr / 1000.0)); } -nframes_t -AudioClock::bbt_frame_from_display (nframes_t pos) const +framepos_t +AudioClock::bbt_frame_from_display (framepos_t pos) const { - if (session == 0) { + if (_session == 0) { error << "AudioClock::current_time() called with BBT mode but without session!" << endmsg; return 0; } @@ -1898,43 +1753,42 @@ AudioClock::bbt_frame_from_display (nframes_t pos) const AnyTime any; any.type = AnyTime::BBT; - any.bbt.bars = atoi (bars_label.get_text()); - any.bbt.beats = atoi (beats_label.get_text()); - any.bbt.ticks = atoi (ticks_label.get_text()); - - if (is_duration) { - any.bbt.bars++; - any.bbt.beats++; - } + any.bbt.bars = atoi (label (Bars)->get_text()); + any.bbt.beats = atoi (label (Beats)->get_text()); + any.bbt.ticks = atoi (label (Ticks)->get_text()); - nframes_t ret = session->convert_to_frames_at (pos, any); - - return ret; + if (is_duration) { + any.bbt.bars++; + any.bbt.beats++; + return _session->any_duration_to_frames (pos, any); + } else { + return _session->convert_to_frames (any); + } } -nframes_t -AudioClock::bbt_frame_duration_from_display (nframes_t pos) const +framepos_t +AudioClock::bbt_frame_duration_from_display (framepos_t pos) const { - if (session == 0) { + if (_session == 0) { error << "AudioClock::current_time() called with BBT mode but without session!" << endmsg; return 0; } - BBT_Time bbt; + Timecode::BBT_Time bbt; - bbt.bars = atoi (bars_label.get_text()); - bbt.beats = atoi (beats_label.get_text()); - bbt.ticks = atoi (ticks_label.get_text()); - - return session->tempo_map().bbt_duration_at(pos,bbt,1); + bbt.bars = atoi (label (Bars)->get_text()); + bbt.beats = atoi (label (Beats)->get_text()); + bbt.ticks = atoi (label (Ticks)->get_text()); + + return _session->tempo_map().bbt_duration_at(pos,bbt,1); } -nframes_t +framepos_t AudioClock::audio_frame_from_display () const { - return (nframes_t) atoi (audio_frames_label.get_text()); + return (framepos_t) atoi (label (AudioFrames)->get_text ()); } void @@ -1944,108 +1798,221 @@ AudioClock::build_ops_menu () ops_menu = new Menu; MenuList& ops_items = ops_menu->items(); ops_menu->set_name ("ArdourContextMenu"); - + if (!Profile->get_sae()) { - ops_items.push_back (MenuElem (_("Timecode"), bind (mem_fun(*this, &AudioClock::set_mode), SMPTE))); + ops_items.push_back (MenuElem (_("Timecode"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), Timecode))); + } + ops_items.push_back (MenuElem (_("Bars:Beats"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), BBT))); + ops_items.push_back (MenuElem (_("Minutes:Seconds"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), MinSec))); + ops_items.push_back (MenuElem (_("Samples"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), Frames))); + + if (editable && !is_duration && !_follows_playhead) { + ops_items.push_back (SeparatorElem()); + ops_items.push_back (MenuElem (_("Set From Playhead"), sigc::mem_fun(*this, &AudioClock::set_from_playhead))); + ops_items.push_back (MenuElem (_("Locate to This Time"), sigc::mem_fun(*this, &AudioClock::locate))); } - ops_items.push_back (MenuElem (_("Bars:Beats"), bind (mem_fun(*this, &AudioClock::set_mode), BBT))); - ops_items.push_back (MenuElem (_("Minutes:Seconds"), bind (mem_fun(*this, &AudioClock::set_mode), MinSec))); - ops_items.push_back (MenuElem (_("Samples"), bind (mem_fun(*this, &AudioClock::set_mode), Frames))); - ops_items.push_back (MenuElem (_("Off"), bind (mem_fun(*this, &AudioClock::set_mode), Off))); } void -AudioClock::set_mode (Mode m) +AudioClock::set_from_playhead () { - /* slightly tricky: this is called from within the ARDOUR_UI - constructor by some of its clock members. at that time - the instance pointer is unset, so we have to be careful. - the main idea is to drop keyboard focus in case we had - started editing the clock and then we switch clock mode. - */ + if (!_session) { + return; + } - clock_base.grab_focus (); - + set (_session->transport_frame()); + ValueChanged (); +} + +void +AudioClock::locate () +{ + if (!_session || is_duration) { + return; + } + + _session->request_locate (current_time(), _session->transport_rolling ()); +} + +void +AudioClock::connect_signals () +{ + scroll_connection = display->scroll.connect (sigc::mem_fun (*this, &AudioClock::scroll)); + button_press_connection = display->button_press.connect (sigc::mem_fun (*this, &AudioClock::button_press)); + button_release_connection = display->button_release.connect (sigc::mem_fun (*this, &AudioClock::button_release)); +} + +void +AudioClock::set_mode (Mode m) +{ if (_mode == m) { return; } - - clock_base.remove (); - + _mode = m; + display->clear_cells (); + + if (supplemental_left) { + supplemental_left->clear_cells (); + supplemental_right->clear_cells (); + } + switch (_mode) { - case SMPTE: - clock_base.add (smpte_packer_hbox); + case Timecode: + display->add_cell (_text_cells[Timecode_Sign]); + display->add_cell (_text_cells[Timecode_Hours]); + display->add_cell (_fixed_cells[Colon1]); + display->add_cell (_text_cells[Timecode_Minutes]); + display->add_cell (_fixed_cells[Colon2]); + display->add_cell (_text_cells[Timecode_Seconds]); + display->add_cell (_fixed_cells[Colon3]); + display->add_cell (_text_cells[Timecode_Frames]); + + if (supplemental_left) { + supplemental_left->add_cell (_text_cells[LowerLeft1]); + supplemental_left->add_cell (_text_cells[LowerLeft2]); + supplemental_right->add_cell (_text_cells[LowerRight1]); + supplemental_right->add_cell (_text_cells[LowerRight2]); + + supplemental_left->set_width_chars (_text_cells[LowerLeft1], 4); + supplemental_left->set_width_chars (_text_cells[LowerLeft2], 8); + + supplemental_right->set_width_chars (_text_cells[LowerRight1], 4); + supplemental_right->set_width_chars (_text_cells[LowerRight2], 6.25); + + supplemental_left->set_text (_text_cells[LowerLeft1], _("EXT")); + supplemental_right->set_text (_text_cells[LowerRight1], _("FPS")); + } break; case BBT: - clock_base.add (bbt_packer_hbox); + display->add_cell (_text_cells[Bars]); + display->add_cell (_fixed_cells[Bar1]); + display->add_cell (_text_cells[Beats]); + display->add_cell (_fixed_cells[Bar2]); + display->add_cell (_text_cells[Ticks]); + if (supplemental_left) { + supplemental_left->add_cell (_text_cells[LowerLeft1]); + supplemental_left->add_cell (_text_cells[LowerLeft2]); + supplemental_right->add_cell (_text_cells[LowerRight1]); + supplemental_right->add_cell (_text_cells[LowerRight2]); + + supplemental_left->set_width_chars (_text_cells[LowerLeft1], 1); + supplemental_left->set_width_chars (_text_cells[LowerLeft2], 5.25); + + supplemental_right->set_width_chars (_text_cells[LowerRight1], 2); // why not 1? M is too wide + supplemental_right->set_width_chars (_text_cells[LowerRight2], 5); + + supplemental_left->set_text (_text_cells[LowerLeft1], _("T")); + supplemental_right->set_text (_text_cells[LowerRight1], _("M")); + } break; case MinSec: - clock_base.add (minsec_packer_hbox); + display->add_cell (_text_cells[MS_Hours]); + display->add_cell (_fixed_cells[Colon1]); + display->add_cell (_text_cells[MS_Minutes]); + display->add_cell (_fixed_cells[Colon2]); + display->add_cell (_text_cells[MS_Seconds]); + display->add_cell (_fixed_cells[Colon3]); + display->add_cell (_text_cells[MS_Milliseconds]); + if (supplemental_left) { + supplemental_left->add_cell (_text_cells[LowerLeft1]); + supplemental_left->add_cell (_text_cells[LowerLeft2]); + supplemental_right->add_cell (_text_cells[LowerRight1]); + supplemental_right->add_cell (_text_cells[LowerRight2]); + + /* These are going to remain empty */ + + supplemental_left->set_width_chars (_text_cells[LowerLeft1], 1); + supplemental_left->set_width_chars (_text_cells[LowerLeft2], 5); + + supplemental_right->set_width_chars (_text_cells[LowerRight1], 1); + supplemental_right->set_width_chars (_text_cells[LowerRight2], 1); + + supplemental_left->set_text (_text_cells[LowerLeft1], _(" ")); + supplemental_right->set_text (_text_cells[LowerRight1], _(" ")); + } break; case Frames: - clock_base.add (frames_packer_hbox); - break; + display->add_cell (_text_cells[AudioFrames]); + if (supplemental_left) { + supplemental_left->add_cell (_text_cells[LowerLeft1]); + supplemental_left->add_cell (_text_cells[LowerLeft2]); + supplemental_right->add_cell (_text_cells[LowerRight1]); + supplemental_right->add_cell (_text_cells[LowerRight2]); + + supplemental_left->set_width_chars (_text_cells[LowerLeft1], 3); + supplemental_left->set_width_chars (_text_cells[LowerLeft2], 5); + + supplemental_right->set_width_chars (_text_cells[LowerRight1], 5); + supplemental_right->set_width_chars (_text_cells[LowerRight2], 5); - case Off: - clock_base.add (off_hbox); + supplemental_left->set_text (_text_cells[LowerLeft1], _("SR")); + supplemental_right->set_text (_text_cells[LowerRight1], _("Pull")); + } break; } - set_size_requests (); - + if (supplemental_left) { + /* clear information cells */ + supplemental_left->set_text (_text_cells[LowerLeft2], _("")); + supplemental_right->set_text (_text_cells[LowerRight2], _("")); + } + set (last_when, true); - clock_base.show_all (); - key_entry_state = 0; - if (!is_transient) { - ModeChanged (); /* EMIT SIGNAL */ - mode_changed (); /* EMIT SIGNAL */ - } + if (!is_transient) { + ModeChanged (); /* EMIT SIGNAL (the static one)*/ + } + + mode_changed (); /* EMIT SIGNAL (the member one) */ } void -AudioClock::set_size_requests () +AudioClock::set_bbt_reference (framepos_t pos) { - /* note that in some fonts, "88" is narrower than "00", hence the 2 pixel padding */ - - switch (_mode) { - case SMPTE: - Gtkmm2ext::set_size_request_to_display_given_text (hours_label, "-00", 5, 5); - Gtkmm2ext::set_size_request_to_display_given_text (minutes_label, "00", 5, 5); - Gtkmm2ext::set_size_request_to_display_given_text (seconds_label, "00", 5, 5); - Gtkmm2ext::set_size_request_to_display_given_text (frames_label, "00", 5, 5); - break; - - case BBT: - Gtkmm2ext::set_size_request_to_display_given_text (bars_label, "-000", 5, 5); - Gtkmm2ext::set_size_request_to_display_given_text (beats_label, "00", 5, 5); - Gtkmm2ext::set_size_request_to_display_given_text (ticks_label, "0000", 5, 5); - break; - - case MinSec: - Gtkmm2ext::set_size_request_to_display_given_text (ms_hours_label, "00", 5, 5); - Gtkmm2ext::set_size_request_to_display_given_text (ms_minutes_label, "00", 5, 5); - Gtkmm2ext::set_size_request_to_display_given_text (ms_seconds_label, "00.000", 5, 5); - break; + bbt_reference_time = pos; +} - case Frames: - Gtkmm2ext::set_size_request_to_display_given_text (audio_frames_label, "0000000000", 5, 5); - break; +void +AudioClock::on_style_changed (const Glib::RefPtr& old_style) +{ + VBox::on_style_changed (old_style); + set_theme (); +} - case Off: - Gtkmm2ext::set_size_request_to_display_given_text (off_hbox, "00000", 5, 5); - break; - +void +AudioClock::set_is_duration (bool yn) +{ + if (yn == is_duration) { + return; } + + is_duration = yn; + set (last_when, true, 0, 's'); } void -AudioClock::set_bbt_reference (nframes64_t pos) +AudioClock::set_off (bool yn) { - bbt_reference_time = pos; + if (_off == yn) { + return; + } + + _off = yn; + + if (_off) { + _canonical_time = current_time (); + _canonical_time_is_displayed = false; + } else { + _canonical_time_is_displayed = true; + } + + /* force a possible redraw */ + + set (_canonical_time, true); } +