another potential fix for partial stripping of a linux bundle
[ardour2.git] / gtk2_ardour / audio_clock.cc
blobdd781c270d7724a02c9301bea920cd7e432ddb9f
1 /*
2 Copyright (C) 1999 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <cstdio> // for sprintf
21 #include <cmath>
23 #include "pbd/convert.h"
24 #include "pbd/enumwriter.h"
26 #include <gtkmm/style.h>
27 #include <gtkmm2ext/utils.h>
29 #include "ardour/ardour.h"
30 #include "ardour/session.h"
31 #include "ardour/tempo.h"
32 #include "ardour/profile.h"
33 #include <sigc++/bind.h>
35 #include "ardour_ui.h"
36 #include "audio_clock.h"
37 #include "utils.h"
38 #include "keyboard.h"
39 #include "gui_thread.h"
40 #include "i18n.h"
42 using namespace ARDOUR;
43 using namespace PBD;
44 using namespace Gtk;
45 using namespace std;
47 using Gtkmm2ext::Keyboard;
49 using PBD::atoi;
50 using PBD::atof;
52 sigc::signal<void> AudioClock::ModeChanged;
53 vector<AudioClock*> AudioClock::clocks;
55 const uint32_t AudioClock::field_length[(int) AudioClock::AudioFrames+1] = {
56 2, /* Timecode_Hours */
57 2, /* Timecode_Minutes */
58 2, /* Timecode_Seconds */
59 2, /* Timecode_Frames */
60 2, /* MS_Hours */
61 2, /* MS_Minutes */
62 5, /* MS_Seconds */
63 3, /* Bars */
64 2, /* Beats */
65 4, /* Tick */
66 10 /* Audio Frame */
69 AudioClock::AudioClock (const string& clock_name, bool transient, const string& widget_name,
70 bool allow_edit, bool follows_playhead, bool duration, bool with_info)
71 : _name (clock_name),
72 is_transient (transient),
73 is_duration (duration),
74 editable (allow_edit),
75 _follows_playhead (follows_playhead),
76 colon1 (":"),
77 colon2 (":"),
78 colon3 (":"),
79 colon4 (":"),
80 colon5 (":"),
81 b1 ("|"),
82 b2 ("|"),
83 last_when(0),
84 _canonical_time_is_displayed (true),
85 _canonical_time (0)
87 last_when = 0;
88 last_pdelta = 0;
89 last_sdelta = 0;
90 key_entry_state = 0;
91 ops_menu = 0;
92 dragging = false;
93 bbt_reference_time = -1;
95 if (with_info) {
96 frames_upper_info_label = manage (new Label);
97 frames_lower_info_label = manage (new Label);
98 timecode_upper_info_label = manage (new Label);
99 timecode_lower_info_label = manage (new Label);
100 bbt_upper_info_label = manage (new Label);
101 bbt_lower_info_label = manage (new Label);
103 frames_upper_info_label->set_name ("AudioClockFramesUpperInfo");
104 frames_lower_info_label->set_name ("AudioClockFramesLowerInfo");
105 timecode_upper_info_label->set_name ("AudioClockTimecodeUpperInfo");
106 timecode_lower_info_label->set_name ("AudioClockTimecodeLowerInfo");
107 bbt_upper_info_label->set_name ("AudioClockBBTUpperInfo");
108 bbt_lower_info_label->set_name ("AudioClockBBTLowerInfo");
110 Gtkmm2ext::set_size_request_to_display_given_text(*timecode_upper_info_label, "23.98",0,0);
111 Gtkmm2ext::set_size_request_to_display_given_text(*timecode_lower_info_label, "NDF",0,0);
113 Gtkmm2ext::set_size_request_to_display_given_text(*bbt_upper_info_label, "88|88",0,0);
114 Gtkmm2ext::set_size_request_to_display_given_text(*bbt_lower_info_label, "888.88",0,0);
116 frames_info_box.pack_start (*frames_upper_info_label, true, true);
117 frames_info_box.pack_start (*frames_lower_info_label, true, true);
118 timecode_info_box.pack_start (*timecode_upper_info_label, true, true);
119 timecode_info_box.pack_start (*timecode_lower_info_label, true, true);
120 bbt_info_box.pack_start (*bbt_upper_info_label, true, true);
121 bbt_info_box.pack_start (*bbt_lower_info_label, true, true);
123 } else {
124 frames_upper_info_label = 0;
125 frames_lower_info_label = 0;
126 timecode_upper_info_label = 0;
127 timecode_lower_info_label = 0;
128 bbt_upper_info_label = 0;
129 bbt_lower_info_label = 0;
132 audio_frames_ebox.add (audio_frames_label);
134 frames_packer.set_homogeneous (false);
135 frames_packer.set_border_width (2);
136 frames_packer.pack_start (audio_frames_ebox, false, false);
138 if (with_info) {
139 frames_packer.pack_start (frames_info_box, false, false, 5);
142 frames_packer_hbox.pack_start (frames_packer, true, false);
144 hours_ebox.add (hours_label);
145 minutes_ebox.add (minutes_label);
146 seconds_ebox.add (seconds_label);
147 frames_ebox.add (frames_label);
148 bars_ebox.add (bars_label);
149 beats_ebox.add (beats_label);
150 ticks_ebox.add (ticks_label);
151 ms_hours_ebox.add (ms_hours_label);
152 ms_minutes_ebox.add (ms_minutes_label);
153 ms_seconds_ebox.add (ms_seconds_label);
155 timecode_packer.set_homogeneous (false);
156 timecode_packer.set_border_width (2);
157 timecode_packer.pack_start (hours_ebox, false, false);
158 timecode_packer.pack_start (colon1, false, false);
159 timecode_packer.pack_start (minutes_ebox, false, false);
160 timecode_packer.pack_start (colon2, false, false);
161 timecode_packer.pack_start (seconds_ebox, false, false);
162 timecode_packer.pack_start (colon3, false, false);
163 timecode_packer.pack_start (frames_ebox, false, false);
165 if (with_info) {
166 timecode_packer.pack_start (timecode_info_box, false, false, 5);
169 timecode_packer_hbox.pack_start (timecode_packer, true, false);
171 bbt_packer.set_homogeneous (false);
172 bbt_packer.set_border_width (2);
173 bbt_packer.pack_start (bars_ebox, false, false);
174 bbt_packer.pack_start (b1, false, false);
175 bbt_packer.pack_start (beats_ebox, false, false);
176 bbt_packer.pack_start (b2, false, false);
177 bbt_packer.pack_start (ticks_ebox, false, false);
179 if (with_info) {
180 bbt_packer.pack_start (bbt_info_box, false, false, 5);
183 bbt_packer_hbox.pack_start (bbt_packer, true, false);
185 minsec_packer.set_homogeneous (false);
186 minsec_packer.set_border_width (2);
187 minsec_packer.pack_start (ms_hours_ebox, false, false);
188 minsec_packer.pack_start (colon4, false, false);
189 minsec_packer.pack_start (ms_minutes_ebox, false, false);
190 minsec_packer.pack_start (colon5, false, false);
191 minsec_packer.pack_start (ms_seconds_ebox, false, false);
193 minsec_packer_hbox.pack_start (minsec_packer, true, false);
195 clock_frame.set_shadow_type (Gtk::SHADOW_IN);
196 clock_frame.set_name ("BaseFrame");
198 clock_frame.add (clock_base);
200 set_widget_name (widget_name);
202 _mode = BBT; /* lie to force mode switch */
203 set_mode (Timecode);
205 pack_start (clock_frame, true, true);
207 /* the clock base handles button releases for menu popup regardless of
208 editable status. if the clock is editable, the clock base is where
209 we pass focus to after leaving the last editable "field", which
210 will then shutdown editing till the user starts it up again.
212 it does this because the focus out event on the field disables
213 keyboard event handling, and we don't connect anything up to
214 notice focus in on the clock base. hence, keyboard event handling
215 stays disabled.
218 clock_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::SCROLL_MASK);
219 clock_base.signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &AudioClock::field_button_release_event), Timecode_Hours));
221 if (editable) {
222 setup_events ();
225 set (last_when, true);
227 if (!is_transient) {
228 clocks.push_back (this);
232 void
233 AudioClock::set_widget_name (string name)
235 Widget::set_name (name);
237 clock_base.set_name (name);
239 audio_frames_label.set_name (name);
240 hours_label.set_name (name);
241 minutes_label.set_name (name);
242 seconds_label.set_name (name);
243 frames_label.set_name (name);
244 bars_label.set_name (name);
245 beats_label.set_name (name);
246 ticks_label.set_name (name);
247 ms_hours_label.set_name (name);
248 ms_minutes_label.set_name (name);
249 ms_seconds_label.set_name (name);
250 hours_ebox.set_name (name);
251 minutes_ebox.set_name (name);
252 seconds_ebox.set_name (name);
253 frames_ebox.set_name (name);
254 audio_frames_ebox.set_name (name);
255 bars_ebox.set_name (name);
256 beats_ebox.set_name (name);
257 ticks_ebox.set_name (name);
258 ms_hours_ebox.set_name (name);
259 ms_minutes_ebox.set_name (name);
260 ms_seconds_ebox.set_name (name);
262 colon1.set_name (name);
263 colon2.set_name (name);
264 colon3.set_name (name);
265 colon4.set_name (name);
266 colon5.set_name (name);
267 b1.set_name (name);
268 b2.set_name (name);
270 queue_draw ();
273 void
274 AudioClock::setup_events ()
276 clock_base.set_flags (Gtk::CAN_FOCUS);
278 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);
279 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);
280 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);
281 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);
282 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);
283 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);
284 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);
285 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);
286 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);
287 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);
288 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);
290 hours_ebox.set_flags (Gtk::CAN_FOCUS);
291 minutes_ebox.set_flags (Gtk::CAN_FOCUS);
292 seconds_ebox.set_flags (Gtk::CAN_FOCUS);
293 frames_ebox.set_flags (Gtk::CAN_FOCUS);
294 audio_frames_ebox.set_flags (Gtk::CAN_FOCUS);
295 bars_ebox.set_flags (Gtk::CAN_FOCUS);
296 beats_ebox.set_flags (Gtk::CAN_FOCUS);
297 ticks_ebox.set_flags (Gtk::CAN_FOCUS);
298 ms_hours_ebox.set_flags (Gtk::CAN_FOCUS);
299 ms_minutes_ebox.set_flags (Gtk::CAN_FOCUS);
300 ms_seconds_ebox.set_flags (Gtk::CAN_FOCUS);
302 hours_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), Timecode_Hours));
303 minutes_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), Timecode_Minutes));
304 seconds_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), Timecode_Seconds));
305 frames_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), Timecode_Frames));
306 audio_frames_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), AudioFrames));
307 bars_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), Bars));
308 beats_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), Beats));
309 ticks_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), Ticks));
310 ms_hours_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), MS_Hours));
311 ms_minutes_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), MS_Minutes));
312 ms_seconds_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), MS_Seconds));
314 hours_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), Timecode_Hours));
315 minutes_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), Timecode_Minutes));
316 seconds_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), Timecode_Seconds));
317 frames_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), Timecode_Frames));
318 audio_frames_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), AudioFrames));
319 bars_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), Bars));
320 beats_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), Beats));
321 ticks_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), Ticks));
322 ms_hours_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), MS_Hours));
323 ms_minutes_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), MS_Minutes));
324 ms_seconds_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), MS_Seconds));
326 hours_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), Timecode_Hours));
327 minutes_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), Timecode_Minutes));
328 seconds_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), Timecode_Seconds));
329 frames_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), Timecode_Frames));
330 audio_frames_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), AudioFrames));
331 bars_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), Bars));
332 beats_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), Beats));
333 ticks_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), Ticks));
334 ms_hours_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), MS_Hours));
335 ms_minutes_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), MS_Minutes));
336 ms_seconds_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), MS_Seconds));
338 hours_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), Timecode_Hours));
339 minutes_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), Timecode_Minutes));
340 seconds_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), Timecode_Seconds));
341 frames_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), Timecode_Frames));
342 audio_frames_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), AudioFrames));
343 bars_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), Bars));
344 beats_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), Beats));
345 ticks_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), Ticks));
346 ms_hours_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), MS_Hours));
347 ms_minutes_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), MS_Minutes));
348 ms_seconds_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), MS_Seconds));
350 hours_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), Timecode_Hours));
351 minutes_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), Timecode_Minutes));
352 seconds_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), Timecode_Seconds));
353 frames_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), Timecode_Frames));
354 audio_frames_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), AudioFrames));
355 bars_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), Bars));
356 beats_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), Beats));
357 ticks_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), Ticks));
358 ms_hours_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), MS_Hours));
359 ms_minutes_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), MS_Minutes));
360 ms_seconds_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), MS_Seconds));
362 hours_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), Timecode_Hours));
363 minutes_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), Timecode_Minutes));
364 seconds_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), Timecode_Seconds));
365 frames_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), Timecode_Frames));
366 audio_frames_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), AudioFrames));
367 bars_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), Bars));
368 beats_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), Beats));
369 ticks_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), Ticks));
370 ms_hours_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), MS_Hours));
371 ms_minutes_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), MS_Minutes));
372 ms_seconds_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), MS_Seconds));
374 hours_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), Timecode_Hours));
375 minutes_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), Timecode_Minutes));
376 seconds_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), Timecode_Seconds));
377 frames_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), Timecode_Frames));
378 audio_frames_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), AudioFrames));
379 bars_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), Bars));
380 beats_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), Beats));
381 ticks_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), Ticks));
382 ms_hours_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), MS_Hours));
383 ms_minutes_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), MS_Minutes));
384 ms_seconds_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), MS_Seconds));
386 hours_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), Timecode_Hours));
387 minutes_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), Timecode_Minutes));
388 seconds_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), Timecode_Seconds));
389 frames_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), Timecode_Frames));
390 audio_frames_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), AudioFrames));
391 bars_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), Bars));
392 beats_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), Beats));
393 ticks_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), Ticks));
394 ms_hours_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), MS_Hours));
395 ms_minutes_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), MS_Minutes));
396 ms_seconds_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), MS_Seconds));
398 clock_base.signal_focus_in_event().connect (sigc::mem_fun (*this, &AudioClock::drop_focus_handler));
401 bool
402 AudioClock::drop_focus_handler (GdkEventFocus*)
404 Keyboard::magic_widget_drop_focus ();
405 return false;
408 void
409 AudioClock::on_realize ()
411 HBox::on_realize ();
413 /* styles are not available until the widgets are bound to a window */
415 set_size_requests ();
418 void
419 AudioClock::set (framepos_t when, bool force, framecnt_t offset, char which)
421 if ((!force && !is_visible()) || _session == 0) {
422 return;
425 bool const pdelta = Config->get_primary_clock_delta_edit_cursor ();
426 bool const sdelta = Config->get_secondary_clock_delta_edit_cursor ();
428 if (offset && which == 'p' && pdelta) {
429 when = (when > offset) ? when - offset : offset - when;
430 } else if (offset && which == 's' && sdelta) {
431 when = (when > offset) ? when - offset : offset - when;
434 if (when == last_when && !force) {
435 return;
438 if (which == 'p' && pdelta && !last_pdelta) {
439 set_widget_name("TransportClockDisplayDelta");
440 last_pdelta = true;
441 } else if (which == 'p' && !pdelta && last_pdelta) {
442 set_widget_name("TransportClockDisplay");
443 last_pdelta = false;
444 } else if (which == 's' && sdelta && !last_sdelta) {
445 set_widget_name("SecondaryClockDisplayDelta");
446 last_sdelta = true;
447 } else if (which == 's' && !sdelta && last_sdelta) {
448 set_widget_name("SecondaryClockDisplay");
449 last_sdelta = false;
452 switch (_mode) {
453 case Timecode:
454 set_timecode (when, force);
455 break;
457 case BBT:
458 set_bbt (when, force);
459 break;
461 case MinSec:
462 set_minsec (when, force);
463 break;
465 case Frames:
466 set_frames (when, force);
467 break;
469 case Off:
470 break;
473 last_when = when;
475 /* we're setting the time from a frames value, so keep it as the canonical value */
476 _canonical_time = when;
477 _canonical_time_is_displayed = false;
480 void
481 AudioClock::session_configuration_changed (std::string p)
483 if (p != "timecode-offset" && p != "timecode-offset-negative") {
484 return;
487 framecnt_t current;
489 switch (_mode) {
490 case Timecode:
491 if (is_duration) {
492 current = current_duration ();
493 } else {
494 current = current_time ();
496 set (current, true);
497 break;
498 default:
499 break;
503 void
504 AudioClock::set_frames (framepos_t when, bool /*force*/)
506 char buf[32];
507 snprintf (buf, sizeof (buf), "%" PRId64, when);
508 audio_frames_label.set_text (buf);
510 if (frames_upper_info_label) {
511 framecnt_t rate = _session->frame_rate();
513 if (fmod (rate, 1000.0) == 0.000) {
514 sprintf (buf, "%" PRId64 "K", rate/1000);
515 } else {
516 sprintf (buf, "%.3fK", rate/1000.0f);
519 if (frames_upper_info_label->get_text() != buf) {
520 frames_upper_info_label->set_text (buf);
523 float vid_pullup = _session->config.get_video_pullup();
525 if (vid_pullup == 0.0) {
526 if (frames_lower_info_label->get_text () != _("none")) {
527 frames_lower_info_label->set_text(_("none"));
529 } else {
530 sprintf (buf, "%-6.4f", vid_pullup);
531 if (frames_lower_info_label->get_text() != buf) {
532 frames_lower_info_label->set_text (buf);
538 void
539 AudioClock::set_minsec (framepos_t when, bool force)
541 char buf[32];
542 framecnt_t left;
543 int hrs;
544 int mins;
545 float secs;
547 left = when;
548 hrs = (int) floor (left / (_session->frame_rate() * 60.0f * 60.0f));
549 left -= (framecnt_t) floor (hrs * _session->frame_rate() * 60.0f * 60.0f);
550 mins = (int) floor (left / (_session->frame_rate() * 60.0f));
551 left -= (framecnt_t) floor (mins * _session->frame_rate() * 60.0f);
552 secs = left / (float) _session->frame_rate();
554 if (force || hrs != ms_last_hrs) {
555 sprintf (buf, "%02d", hrs);
556 ms_hours_label.set_text (buf);
557 ms_last_hrs = hrs;
560 if (force || mins != ms_last_mins) {
561 sprintf (buf, "%02d", mins);
562 ms_minutes_label.set_text (buf);
563 ms_last_mins = mins;
566 if (force || secs != ms_last_secs) {
567 sprintf (buf, "%06.3f", secs);
568 ms_seconds_label.set_text (buf);
569 ms_last_secs = secs;
573 void
574 AudioClock::set_timecode (framepos_t when, bool force)
576 char buf[32];
577 Timecode::Time timecode;
579 if (is_duration) {
580 _session->timecode_duration (when, timecode);
581 } else {
582 _session->timecode_time (when, timecode);
585 if (force || timecode.hours != last_hrs || timecode.negative != last_negative) {
586 if (timecode.negative) {
587 sprintf (buf, "-%02" PRIu32, timecode.hours);
588 } else {
589 sprintf (buf, " %02" PRIu32, timecode.hours);
591 hours_label.set_text (buf);
592 last_hrs = timecode.hours;
593 last_negative = timecode.negative;
596 if (force || timecode.minutes != last_mins) {
597 sprintf (buf, "%02" PRIu32, timecode.minutes);
598 minutes_label.set_text (buf);
599 last_mins = timecode.minutes;
602 if (force || timecode.seconds != last_secs) {
603 sprintf (buf, "%02" PRIu32, timecode.seconds);
604 seconds_label.set_text (buf);
605 last_secs = timecode.seconds;
608 if (force || timecode.frames != last_frames) {
609 sprintf (buf, "%02" PRIu32, timecode.frames);
610 frames_label.set_text (buf);
611 last_frames = timecode.frames;
614 if (timecode_upper_info_label) {
615 double timecode_frames = _session->timecode_frames_per_second();
617 if ( fmod(timecode_frames, 1.0) == 0.0) {
618 sprintf (buf, "%u", int (timecode_frames));
619 } else {
620 sprintf (buf, "%.2f", timecode_frames);
623 if (timecode_upper_info_label->get_text() != buf) {
624 timecode_upper_info_label->set_text (buf);
627 if ((fabs(timecode_frames - 29.97) < 0.0001) || timecode_frames == 30) {
628 if (_session->timecode_drop_frames()) {
629 sprintf (buf, "DF");
630 } else {
631 sprintf (buf, "NDF");
633 } else {
634 // there is no drop frame alternative
635 buf[0] = '\0';
638 if (timecode_lower_info_label->get_text() != buf) {
639 timecode_lower_info_label->set_text (buf);
644 void
645 AudioClock::set_bbt (framepos_t when, bool force)
647 char buf[16];
648 Timecode::BBT_Time bbt;
650 /* handle a common case */
651 if (is_duration) {
652 if (when == 0) {
653 bbt.bars = 0;
654 bbt.beats = 0;
655 bbt.ticks = 0;
656 } else {
657 _session->tempo_map().bbt_time (when, bbt);
658 bbt.bars--;
659 bbt.beats--;
661 } else {
662 _session->tempo_map().bbt_time (when, bbt);
665 sprintf (buf, "%03" PRIu32, bbt.bars);
666 if (force || bars_label.get_text () != buf) {
667 bars_label.set_text (buf);
669 sprintf (buf, "%02" PRIu32, bbt.beats);
670 if (force || beats_label.get_text () != buf) {
671 beats_label.set_text (buf);
673 sprintf (buf, "%04" PRIu32, bbt.ticks);
674 if (force || ticks_label.get_text () != buf) {
675 ticks_label.set_text (buf);
678 if (bbt_upper_info_label) {
679 framepos_t pos;
681 if (bbt_reference_time < 0) {
682 pos = when;
683 } else {
684 pos = bbt_reference_time;
687 TempoMetric m (_session->tempo_map().metric_at (pos));
689 sprintf (buf, "%-5.2f", m.tempo().beats_per_minute());
690 if (bbt_lower_info_label->get_text() != buf) {
691 bbt_lower_info_label->set_text (buf);
693 sprintf (buf, "%g|%g", m.meter().beats_per_bar(), m.meter().note_divisor());
694 if (bbt_upper_info_label->get_text() != buf) {
695 bbt_upper_info_label->set_text (buf);
700 void
701 AudioClock::set_session (Session *s)
703 SessionHandlePtr::set_session (s);
705 if (_session) {
707 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&AudioClock::session_configuration_changed, this, _1), gui_context());
709 XMLProperty* prop;
710 XMLNode* node = _session->extra_xml (X_("ClockModes"));
711 AudioClock::Mode amode;
713 if (node) {
714 if ((prop = node->property (_name)) != 0) {
715 amode = AudioClock::Mode (string_2_enum (prop->value(), amode));
716 set_mode (amode);
720 set (last_when, true);
724 void
725 AudioClock::focus ()
727 switch (_mode) {
728 case Timecode:
729 hours_ebox.grab_focus ();
730 break;
732 case BBT:
733 bars_ebox.grab_focus ();
734 break;
736 case MinSec:
737 ms_hours_ebox.grab_focus ();
738 break;
740 case Frames:
741 frames_ebox.grab_focus ();
742 break;
744 case Off:
745 break;
750 bool
751 AudioClock::field_key_press_event (GdkEventKey */*ev*/, Field /*field*/)
753 /* all key activity is handled on key release */
754 return true;
757 bool
758 AudioClock::field_key_release_event (GdkEventKey *ev, Field field)
760 Label *label = 0;
761 string new_text;
762 char new_char = 0;
763 bool move_on = false;
765 switch (field) {
766 case Timecode_Hours:
767 label = &hours_label;
768 break;
769 case Timecode_Minutes:
770 label = &minutes_label;
771 break;
772 case Timecode_Seconds:
773 label = &seconds_label;
774 break;
775 case Timecode_Frames:
776 label = &frames_label;
777 break;
779 case AudioFrames:
780 label = &audio_frames_label;
781 break;
783 case MS_Hours:
784 label = &ms_hours_label;
785 break;
786 case MS_Minutes:
787 label = &ms_minutes_label;
788 break;
789 case MS_Seconds:
790 label = &ms_seconds_label;
791 break;
793 case Bars:
794 label = &bars_label;
795 break;
796 case Beats:
797 label = &beats_label;
798 break;
799 case Ticks:
800 label = &ticks_label;
801 break;
802 default:
803 return false;
806 switch (ev->keyval) {
807 case GDK_0:
808 case GDK_KP_0:
809 new_char = '0';
810 break;
811 case GDK_1:
812 case GDK_KP_1:
813 new_char = '1';
814 break;
815 case GDK_2:
816 case GDK_KP_2:
817 new_char = '2';
818 break;
819 case GDK_3:
820 case GDK_KP_3:
821 new_char = '3';
822 break;
823 case GDK_4:
824 case GDK_KP_4:
825 new_char = '4';
826 break;
827 case GDK_5:
828 case GDK_KP_5:
829 new_char = '5';
830 break;
831 case GDK_6:
832 case GDK_KP_6:
833 new_char = '6';
834 break;
835 case GDK_7:
836 case GDK_KP_7:
837 new_char = '7';
838 break;
839 case GDK_8:
840 case GDK_KP_8:
841 new_char = '8';
842 break;
843 case GDK_9:
844 case GDK_KP_9:
845 new_char = '9';
846 break;
848 case GDK_period:
849 case GDK_KP_Decimal:
850 if (_mode == MinSec && field == MS_Seconds) {
851 new_char = '.';
852 } else {
853 return false;
855 break;
857 case GDK_Tab:
858 case GDK_Return:
859 case GDK_KP_Enter:
860 move_on = true;
861 break;
863 case GDK_Escape:
864 key_entry_state = 0;
865 clock_base.grab_focus ();
866 ChangeAborted(); /* EMIT SIGNAL */
867 return true;
869 default:
870 return false;
873 if (!move_on) {
875 if (key_entry_state == 0) {
877 /* initialize with a fresh new string */
879 if (field != AudioFrames) {
880 for (uint32_t xn = 0; xn < field_length[field] - 1; ++xn) {
881 new_text += '0';
883 } else {
884 new_text = "";
887 } else {
889 string existing = label->get_text();
890 if (existing.length() >= field_length[field]) {
891 new_text = existing.substr (1, field_length[field] - 1);
892 } else {
893 new_text = existing.substr (0, field_length[field] - 1);
897 new_text += new_char;
898 label->set_text (new_text);
899 _canonical_time_is_displayed = true;
900 key_entry_state++;
903 if (key_entry_state == field_length[field]) {
904 move_on = true;
907 if (move_on) {
909 if (key_entry_state) {
911 switch (field) {
912 case Timecode_Hours:
913 case Timecode_Minutes:
914 case Timecode_Seconds:
915 case Timecode_Frames:
916 // Check Timecode fields for sanity (may also adjust fields)
917 timecode_sanitize_display();
918 break;
919 case Bars:
920 case Beats:
921 case Ticks:
922 // Bars should never be, unless this clock is for a duration
923 if (atoi(bars_label.get_text()) == 0 && !is_duration) {
924 bars_label.set_text("001");
925 _canonical_time_is_displayed = true;
927 // beats should never be 0, unless this clock is for a duration
928 if (atoi(beats_label.get_text()) == 0 && !is_duration) {
929 beats_label.set_text("01");
930 _canonical_time_is_displayed = true;
932 break;
933 default:
934 break;
937 ValueChanged(); /* EMIT_SIGNAL */
940 /* move on to the next field.
943 switch (field) {
945 /* Timecode */
947 case Timecode_Hours:
948 minutes_ebox.grab_focus ();
949 break;
950 case Timecode_Minutes:
951 seconds_ebox.grab_focus ();
952 break;
953 case Timecode_Seconds:
954 frames_ebox.grab_focus ();
955 break;
956 case Timecode_Frames:
957 clock_base.grab_focus ();
958 break;
960 /* audio frames */
961 case AudioFrames:
962 clock_base.grab_focus ();
963 break;
965 /* Min:Sec */
967 case MS_Hours:
968 ms_minutes_ebox.grab_focus ();
969 break;
970 case MS_Minutes:
971 ms_seconds_ebox.grab_focus ();
972 break;
973 case MS_Seconds:
974 clock_base.grab_focus ();
975 break;
977 /* BBT */
979 case Bars:
980 beats_ebox.grab_focus ();
981 break;
982 case Beats:
983 ticks_ebox.grab_focus ();
984 break;
985 case Ticks:
986 clock_base.grab_focus ();
987 break;
989 default:
990 break;
995 //if user hit Enter, lose focus
996 switch (ev->keyval) {
997 case GDK_Return:
998 case GDK_KP_Enter:
999 clock_base.grab_focus ();
1002 return true;
1005 bool
1006 AudioClock::field_focus_in_event (GdkEventFocus */*ev*/, Field field)
1008 key_entry_state = 0;
1010 Keyboard::magic_widget_grab_focus ();
1012 switch (field) {
1013 case Timecode_Hours:
1014 hours_ebox.set_flags (Gtk::HAS_FOCUS);
1015 hours_ebox.set_state (Gtk::STATE_ACTIVE);
1016 break;
1017 case Timecode_Minutes:
1018 minutes_ebox.set_flags (Gtk::HAS_FOCUS);
1019 minutes_ebox.set_state (Gtk::STATE_ACTIVE);
1020 break;
1021 case Timecode_Seconds:
1022 seconds_ebox.set_flags (Gtk::HAS_FOCUS);
1023 seconds_ebox.set_state (Gtk::STATE_ACTIVE);
1024 break;
1025 case Timecode_Frames:
1026 frames_ebox.set_flags (Gtk::HAS_FOCUS);
1027 frames_ebox.set_state (Gtk::STATE_ACTIVE);
1028 break;
1030 case AudioFrames:
1031 audio_frames_ebox.set_flags (Gtk::HAS_FOCUS);
1032 audio_frames_ebox.set_state (Gtk::STATE_ACTIVE);
1033 break;
1035 case MS_Hours:
1036 ms_hours_ebox.set_flags (Gtk::HAS_FOCUS);
1037 ms_hours_ebox.set_state (Gtk::STATE_ACTIVE);
1038 break;
1039 case MS_Minutes:
1040 ms_minutes_ebox.set_flags (Gtk::HAS_FOCUS);
1041 ms_minutes_ebox.set_state (Gtk::STATE_ACTIVE);
1042 break;
1043 case MS_Seconds:
1044 ms_seconds_ebox.set_flags (Gtk::HAS_FOCUS);
1045 ms_seconds_ebox.set_state (Gtk::STATE_ACTIVE);
1046 break;
1047 case Bars:
1048 bars_ebox.set_flags (Gtk::HAS_FOCUS);
1049 bars_ebox.set_state (Gtk::STATE_ACTIVE);
1050 break;
1051 case Beats:
1052 beats_ebox.set_flags (Gtk::HAS_FOCUS);
1053 beats_ebox.set_state (Gtk::STATE_ACTIVE);
1054 break;
1055 case Ticks:
1056 ticks_ebox.set_flags (Gtk::HAS_FOCUS);
1057 ticks_ebox.set_state (Gtk::STATE_ACTIVE);
1058 break;
1061 return false;
1064 bool
1065 AudioClock::field_focus_out_event (GdkEventFocus */*ev*/, Field field)
1067 switch (field) {
1069 case Timecode_Hours:
1070 hours_ebox.unset_flags (Gtk::HAS_FOCUS);
1071 hours_ebox.set_state (Gtk::STATE_NORMAL);
1072 break;
1073 case Timecode_Minutes:
1074 minutes_ebox.unset_flags (Gtk::HAS_FOCUS);
1075 minutes_ebox.set_state (Gtk::STATE_NORMAL);
1076 break;
1077 case Timecode_Seconds:
1078 seconds_ebox.unset_flags (Gtk::HAS_FOCUS);
1079 seconds_ebox.set_state (Gtk::STATE_NORMAL);
1080 break;
1081 case Timecode_Frames:
1082 frames_ebox.unset_flags (Gtk::HAS_FOCUS);
1083 frames_ebox.set_state (Gtk::STATE_NORMAL);
1084 break;
1086 case AudioFrames:
1087 audio_frames_ebox.unset_flags (Gtk::HAS_FOCUS);
1088 audio_frames_ebox.set_state (Gtk::STATE_NORMAL);
1089 break;
1091 case MS_Hours:
1092 ms_hours_ebox.unset_flags (Gtk::HAS_FOCUS);
1093 ms_hours_ebox.set_state (Gtk::STATE_NORMAL);
1094 break;
1095 case MS_Minutes:
1096 ms_minutes_ebox.unset_flags (Gtk::HAS_FOCUS);
1097 ms_minutes_ebox.set_state (Gtk::STATE_NORMAL);
1098 break;
1099 case MS_Seconds:
1100 ms_seconds_ebox.unset_flags (Gtk::HAS_FOCUS);
1101 ms_seconds_ebox.set_state (Gtk::STATE_NORMAL);
1102 break;
1104 case Bars:
1105 bars_ebox.unset_flags (Gtk::HAS_FOCUS);
1106 bars_ebox.set_state (Gtk::STATE_NORMAL);
1107 break;
1108 case Beats:
1109 beats_ebox.unset_flags (Gtk::HAS_FOCUS);
1110 beats_ebox.set_state (Gtk::STATE_NORMAL);
1111 break;
1112 case Ticks:
1113 ticks_ebox.unset_flags (Gtk::HAS_FOCUS);
1114 ticks_ebox.set_state (Gtk::STATE_NORMAL);
1115 break;
1118 Keyboard::magic_widget_drop_focus ();
1120 return false;
1123 bool
1124 AudioClock::field_button_release_event (GdkEventButton *ev, Field field)
1126 if (dragging) {
1127 cerr << "button event on clock but we are dragging\n";
1128 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1129 dragging = false;
1130 if (ev->y > drag_start_y+1 || ev->y < drag_start_y-1 || Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)){
1131 // we actually dragged so return without setting editing focus, or we shift clicked
1132 return true;
1136 if (!editable) {
1137 if (ops_menu == 0) {
1138 build_ops_menu ();
1140 ops_menu->popup (1, ev->time);
1141 return true;
1144 if (Keyboard::is_context_menu_event (ev)) {
1145 if (ops_menu == 0) {
1146 build_ops_menu ();
1148 ops_menu->popup (1, ev->time);
1149 return true;
1152 switch (ev->button) {
1153 case 1:
1154 switch (field) {
1155 case Timecode_Hours:
1156 hours_ebox.grab_focus();
1157 break;
1158 case Timecode_Minutes:
1159 minutes_ebox.grab_focus();
1160 break;
1161 case Timecode_Seconds:
1162 seconds_ebox.grab_focus();
1163 break;
1164 case Timecode_Frames:
1165 frames_ebox.grab_focus();
1166 break;
1168 case AudioFrames:
1169 audio_frames_ebox.grab_focus();
1170 break;
1172 case MS_Hours:
1173 ms_hours_ebox.grab_focus();
1174 break;
1175 case MS_Minutes:
1176 ms_minutes_ebox.grab_focus();
1177 break;
1178 case MS_Seconds:
1179 ms_seconds_ebox.grab_focus();
1180 break;
1182 case Bars:
1183 bars_ebox.grab_focus ();
1184 break;
1185 case Beats:
1186 beats_ebox.grab_focus ();
1187 break;
1188 case Ticks:
1189 ticks_ebox.grab_focus ();
1190 break;
1192 break;
1194 default:
1195 break;
1198 return true;
1201 bool
1202 AudioClock::field_button_press_event (GdkEventButton *ev, Field /*field*/)
1204 if (_session == 0) {
1205 return false;
1208 framepos_t frames = 0;
1210 switch (ev->button) {
1211 case 1:
1212 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
1213 set (frames, true);
1214 ValueChanged (); /* EMIT_SIGNAL */
1217 /* make absolutely sure that the pointer is grabbed */
1218 gdk_pointer_grab(ev->window,false ,
1219 GdkEventMask( Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK |Gdk::BUTTON_RELEASE_MASK),
1220 NULL,NULL,ev->time);
1221 dragging = true;
1222 drag_accum = 0;
1223 drag_start_y = ev->y;
1224 drag_y = ev->y;
1225 break;
1227 case 2:
1228 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
1229 set (frames, true);
1230 ValueChanged (); /* EMIT_SIGNAL */
1232 break;
1234 case 3:
1235 /* used for context sensitive menu */
1236 return false;
1237 break;
1239 default:
1240 return false;
1241 break;
1244 return true;
1247 bool
1248 AudioClock::field_button_scroll_event (GdkEventScroll *ev, Field field)
1250 if (_session == 0) {
1251 return false;
1254 framepos_t frames = 0;
1256 switch (ev->direction) {
1258 case GDK_SCROLL_UP:
1259 frames = get_frames (field);
1260 if (frames != 0) {
1261 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1262 frames *= 10;
1264 set (current_time() + frames, true);
1265 ValueChanged (); /* EMIT_SIGNAL */
1267 break;
1269 case GDK_SCROLL_DOWN:
1270 frames = get_frames (field);
1271 if (frames != 0) {
1272 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1273 frames *= 10;
1276 if ((double)current_time() - (double)frames < 0.0) {
1277 set (0, true);
1278 } else {
1279 set (current_time() - frames, true);
1282 ValueChanged (); /* EMIT_SIGNAL */
1284 break;
1286 default:
1287 return false;
1288 break;
1291 return true;
1294 bool
1295 AudioClock::field_motion_notify_event (GdkEventMotion *ev, Field field)
1297 if (_session == 0 || !dragging) {
1298 return false;
1301 float pixel_frame_scale_factor = 0.2f;
1304 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1305 pixel_frame_scale_factor = 0.1f;
1309 if (Keyboard::modifier_state_contains (ev->state,
1310 Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)) {
1312 pixel_frame_scale_factor = 0.025f;
1315 double y_delta = ev->y - drag_y;
1317 drag_accum += y_delta*pixel_frame_scale_factor;
1319 drag_y = ev->y;
1321 if (trunc(drag_accum) != 0) {
1323 framepos_t frames;
1324 framepos_t pos;
1325 int dir;
1326 dir = (drag_accum < 0 ? 1:-1);
1327 pos = current_time();
1328 frames = get_frames (field,pos,dir);
1330 if (frames != 0 && frames * drag_accum < current_time()) {
1332 set ((framepos_t) floor (pos - drag_accum * frames), false); // minus because up is negative in computer-land
1334 } else {
1335 set (0 , false);
1339 drag_accum= 0;
1340 ValueChanged(); /* EMIT_SIGNAL */
1345 return true;
1348 framepos_t
1349 AudioClock::get_frames (Field field, framepos_t pos, int dir)
1351 framecnt_t frames = 0;
1352 Timecode::BBT_Time bbt;
1353 switch (field) {
1354 case Timecode_Hours:
1355 frames = (framecnt_t) floor (3600.0 * _session->frame_rate());
1356 break;
1357 case Timecode_Minutes:
1358 frames = (framecnt_t) floor (60.0 * _session->frame_rate());
1359 break;
1360 case Timecode_Seconds:
1361 frames = _session->frame_rate();
1362 break;
1363 case Timecode_Frames:
1364 frames = (framecnt_t) floor (_session->frame_rate() / _session->timecode_frames_per_second());
1365 break;
1367 case AudioFrames:
1368 frames = 1;
1369 break;
1371 case MS_Hours:
1372 frames = (framecnt_t) floor (3600.0 * _session->frame_rate());
1373 break;
1374 case MS_Minutes:
1375 frames = (framecnt_t) floor (60.0 * _session->frame_rate());
1376 break;
1377 case MS_Seconds:
1378 frames = _session->frame_rate();
1379 break;
1381 case Bars:
1382 bbt.bars = 1;
1383 bbt.beats = 0;
1384 bbt.ticks = 0;
1385 frames = _session->tempo_map().bbt_duration_at(pos,bbt,dir);
1386 break;
1387 case Beats:
1388 bbt.bars = 0;
1389 bbt.beats = 1;
1390 bbt.ticks = 0;
1391 frames = _session->tempo_map().bbt_duration_at(pos,bbt,dir);
1392 break;
1393 case Ticks:
1394 bbt.bars = 0;
1395 bbt.beats = 0;
1396 bbt.ticks = 1;
1397 frames = _session->tempo_map().bbt_duration_at(pos,bbt,dir);
1398 break;
1401 return frames;
1404 framepos_t
1405 AudioClock::current_time (framepos_t pos) const
1407 if (!_canonical_time_is_displayed) {
1408 return _canonical_time;
1411 framepos_t ret = 0;
1413 switch (_mode) {
1414 case Timecode:
1415 ret = timecode_frame_from_display ();
1416 break;
1417 case BBT:
1418 ret = bbt_frame_from_display (pos);
1419 break;
1421 case MinSec:
1422 ret = minsec_frame_from_display ();
1423 break;
1425 case Frames:
1426 ret = audio_frame_from_display ();
1427 break;
1429 case Off:
1430 break;
1433 return ret;
1436 framepos_t
1437 AudioClock::current_duration (framepos_t pos) const
1439 framepos_t ret = 0;
1441 switch (_mode) {
1442 case Timecode:
1443 ret = timecode_frame_from_display ();
1444 break;
1445 case BBT:
1446 ret = bbt_frame_duration_from_display (pos);
1447 break;
1449 case MinSec:
1450 ret = minsec_frame_from_display ();
1451 break;
1453 case Frames:
1454 ret = audio_frame_from_display ();
1455 break;
1457 case Off:
1458 break;
1461 return ret;
1464 void
1465 AudioClock::timecode_sanitize_display()
1467 // Check Timecode fields for sanity, possibly adjusting values
1468 if (atoi(minutes_label.get_text()) > 59) {
1469 minutes_label.set_text("59");
1470 _canonical_time_is_displayed = true;
1473 if (atoi(seconds_label.get_text()) > 59) {
1474 seconds_label.set_text("59");
1475 _canonical_time_is_displayed = true;
1478 switch ((long)rint(_session->timecode_frames_per_second())) {
1479 case 24:
1480 if (atoi(frames_label.get_text()) > 23) {
1481 frames_label.set_text("23");
1482 _canonical_time_is_displayed = true;
1484 break;
1485 case 25:
1486 if (atoi(frames_label.get_text()) > 24) {
1487 frames_label.set_text("24");
1488 _canonical_time_is_displayed = true;
1490 break;
1491 case 30:
1492 if (atoi(frames_label.get_text()) > 29) {
1493 frames_label.set_text("29");
1494 _canonical_time_is_displayed = true;
1496 break;
1497 default:
1498 break;
1501 if (_session->timecode_drop_frames()) {
1502 if ((atoi(minutes_label.get_text()) % 10) && (atoi(seconds_label.get_text()) == 0) && (atoi(frames_label.get_text()) < 2)) {
1503 frames_label.set_text("02");
1504 _canonical_time_is_displayed = true;
1509 framepos_t
1510 AudioClock::timecode_frame_from_display () const
1512 if (_session == 0) {
1513 return 0;
1516 Timecode::Time timecode;
1517 framepos_t sample;
1519 timecode.hours = atoi (hours_label.get_text());
1520 timecode.minutes = atoi (minutes_label.get_text());
1521 timecode.seconds = atoi (seconds_label.get_text());
1522 timecode.frames = atoi (frames_label.get_text());
1523 timecode.rate = _session->timecode_frames_per_second();
1524 timecode.drop= _session->timecode_drop_frames();
1526 _session->timecode_to_sample( timecode, sample, false /* use_offset */, false /* use_subframes */ );
1529 #if 0
1530 #define Timecode_SAMPLE_TEST_1
1531 #define Timecode_SAMPLE_TEST_2
1532 #define Timecode_SAMPLE_TEST_3
1533 #define Timecode_SAMPLE_TEST_4
1534 #define Timecode_SAMPLE_TEST_5
1535 #define Timecode_SAMPLE_TEST_6
1536 #define Timecode_SAMPLE_TEST_7
1538 // Testcode for timecode<->sample conversions (P.S.)
1539 Timecode::Time timecode1;
1540 framepos_t sample1;
1541 framepos_t oldsample = 0;
1542 Timecode::Time timecode2;
1543 framecnt_t sample_increment;
1545 sample_increment = (framecnt_t)rint(_session->frame_rate() / _session->timecode_frames_per_second);
1547 #ifdef Timecode_SAMPLE_TEST_1
1548 // Test 1: use_offset = false, use_subframes = false
1549 cout << "use_offset = false, use_subframes = false" << endl;
1550 for (int i = 0; i < 108003; i++) {
1551 _session->timecode_to_sample( timecode1, sample1, false /* use_offset */, false /* use_subframes */ );
1552 _session->sample_to_timecode( sample1, timecode2, false /* use_offset */, false /* use_subframes */ );
1554 if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) {
1555 cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1556 cout << "timecode1: " << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1557 cout << "sample: " << sample1 << endl;
1558 cout << "sample: " << sample1 << " -> ";
1559 cout << "timecode2: " << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1560 break;
1563 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1564 cout << "ERROR: timecode2 not equal timecode1" << endl;
1565 cout << "timecode1: " << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1566 cout << "sample: " << sample1 << endl;
1567 cout << "sample: " << sample1 << " -> ";
1568 cout << "timecode2: " << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1569 break;
1571 oldsample = sample1;
1572 _session->timecode_increment( timecode1 );
1575 cout << "sample_increment: " << sample_increment << endl;
1576 cout << "sample: " << sample1 << " -> ";
1577 cout << "timecode: " << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1578 #endif
1580 #ifdef Timecode_SAMPLE_TEST_2
1581 // Test 2: use_offset = true, use_subframes = false
1582 cout << "use_offset = true, use_subframes = false" << endl;
1584 timecode1.hours = 0;
1585 timecode1.minutes = 0;
1586 timecode1.seconds = 0;
1587 timecode1.frames = 0;
1588 timecode1.subframes = 0;
1589 sample1 = oldsample = 0;
1591 _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1592 cout << "Starting at sample: " << sample1 << " -> ";
1593 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1595 for (int i = 0; i < 108003; i++) {
1596 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1597 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1599 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1600 // cout << "sample: " << sample1 << endl;
1601 // cout << "sample: " << sample1 << " -> ";
1602 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1604 if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) {
1605 cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1606 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1607 cout << "sample: " << sample1 << endl;
1608 cout << "sample: " << sample1 << " -> ";
1609 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1610 break;
1613 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1614 cout << "ERROR: timecode2 not equal timecode1" << endl;
1615 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1616 cout << "sample: " << sample1 << endl;
1617 cout << "sample: " << sample1 << " -> ";
1618 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1619 break;
1621 oldsample = sample1;
1622 _session->timecode_increment( timecode1 );
1625 cout << "sample_increment: " << sample_increment << endl;
1626 cout << "sample: " << sample1 << " -> ";
1627 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1628 #endif
1630 #ifdef Timecode_SAMPLE_TEST_3
1631 // Test 3: use_offset = true, use_subframes = false, decrement
1632 cout << "use_offset = true, use_subframes = false, decrement" << endl;
1634 _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1635 cout << "Starting at sample: " << sample1 << " -> ";
1636 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1638 for (int i = 0; i < 108003; i++) {
1639 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1640 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1642 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1643 // cout << "sample: " << sample1 << endl;
1644 // cout << "sample: " << sample1 << " -> ";
1645 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1647 if ((i > 0) && ( ((oldsample - sample1) != sample_increment) && ((oldsample - sample1) != (sample_increment + 1)) && ((oldsample - sample1) != (sample_increment - 1)))) {
1648 cout << "ERROR: sample increment not right: " << (oldsample - sample1) << " != " << sample_increment << endl;
1649 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1650 cout << "sample: " << sample1 << endl;
1651 cout << "sample: " << sample1 << " -> ";
1652 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1653 break;
1656 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1657 cout << "ERROR: timecode2 not equal timecode1" << endl;
1658 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1659 cout << "sample: " << sample1 << endl;
1660 cout << "sample: " << sample1 << " -> ";
1661 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1662 break;
1664 oldsample = sample1;
1665 _session->timecode_decrement( timecode1 );
1668 cout << "sample_decrement: " << sample_increment << endl;
1669 cout << "sample: " << sample1 << " -> ";
1670 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1671 #endif
1674 #ifdef Timecode_SAMPLE_TEST_4
1675 // Test 4: use_offset = true, use_subframes = true
1676 cout << "use_offset = true, use_subframes = true" << endl;
1678 for (long sub = 5; sub < 80; sub += 5) {
1679 timecode1.hours = 0;
1680 timecode1.minutes = 0;
1681 timecode1.seconds = 0;
1682 timecode1.frames = 0;
1683 timecode1.subframes = 0;
1684 sample1 = oldsample = (sample_increment * sub) / 80;
1686 _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, true /* use_subframes */ );
1688 cout << "starting at sample: " << sample1 << " -> ";
1689 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1691 for (int i = 0; i < 108003; i++) {
1692 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, true /* use_subframes */ );
1693 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, true /* use_subframes */ );
1695 if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) {
1696 cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1697 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1698 cout << "sample: " << sample1 << endl;
1699 cout << "sample: " << sample1 << " -> ";
1700 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1701 //break;
1704 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames || timecode2.subframes != timecode1.subframes) {
1705 cout << "ERROR: timecode2 not equal timecode1" << endl;
1706 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1707 cout << "sample: " << sample1 << endl;
1708 cout << "sample: " << sample1 << " -> ";
1709 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1710 break;
1712 oldsample = sample1;
1713 _session->timecode_increment( timecode1 );
1716 cout << "sample_increment: " << sample_increment << endl;
1717 cout << "sample: " << sample1 << " -> ";
1718 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1720 for (int i = 0; i < 108003; i++) {
1721 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, true /* use_subframes */ );
1722 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, true /* use_subframes */ );
1724 if ((i > 0) && ( ((oldsample - sample1) != sample_increment) && ((oldsample - sample1) != (sample_increment + 1)) && ((oldsample - sample1) != (sample_increment - 1)))) {
1725 cout << "ERROR: sample increment not right: " << (oldsample - sample1) << " != " << sample_increment << endl;
1726 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1727 cout << "sample: " << sample1 << endl;
1728 cout << "sample: " << sample1 << " -> ";
1729 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1730 //break;
1733 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames || timecode2.subframes != timecode1.subframes) {
1734 cout << "ERROR: timecode2 not equal timecode1" << endl;
1735 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1736 cout << "sample: " << sample1 << endl;
1737 cout << "sample: " << sample1 << " -> ";
1738 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1739 break;
1741 oldsample = sample1;
1742 _session->timecode_decrement( timecode1 );
1745 cout << "sample_decrement: " << sample_increment << endl;
1746 cout << "sample: " << sample1 << " -> ";
1747 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1749 #endif
1752 #ifdef Timecode_SAMPLE_TEST_5
1753 // Test 5: use_offset = true, use_subframes = false, increment seconds
1754 cout << "use_offset = true, use_subframes = false, increment seconds" << endl;
1756 timecode1.hours = 0;
1757 timecode1.minutes = 0;
1758 timecode1.seconds = 0;
1759 timecode1.frames = 0;
1760 timecode1.subframes = 0;
1761 sample1 = oldsample = 0;
1762 sample_increment = _session->frame_rate();
1764 _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1765 cout << "Starting at sample: " << sample1 << " -> ";
1766 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1768 for (int i = 0; i < 3600; i++) {
1769 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1770 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1772 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1773 // cout << "sample: " << sample1 << endl;
1774 // cout << "sample: " << sample1 << " -> ";
1775 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1777 // if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1))))
1778 // {
1779 // cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1780 // break;
1781 // }
1783 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1784 cout << "ERROR: timecode2 not equal timecode1" << endl;
1785 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1786 cout << "sample: " << sample1 << endl;
1787 cout << "sample: " << sample1 << " -> ";
1788 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1789 break;
1791 oldsample = sample1;
1792 _session->timecode_increment_seconds( timecode1 );
1795 cout << "sample_increment: " << sample_increment << endl;
1796 cout << "sample: " << sample1 << " -> ";
1797 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1798 #endif
1801 #ifdef Timecode_SAMPLE_TEST_6
1802 // Test 6: use_offset = true, use_subframes = false, increment minutes
1803 cout << "use_offset = true, use_subframes = false, increment minutes" << endl;
1805 timecode1.hours = 0;
1806 timecode1.minutes = 0;
1807 timecode1.seconds = 0;
1808 timecode1.frames = 0;
1809 timecode1.subframes = 0;
1810 sample1 = oldsample = 0;
1811 sample_increment = _session->frame_rate() * 60;
1813 _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1814 cout << "Starting at sample: " << sample1 << " -> ";
1815 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1817 for (int i = 0; i < 60; i++) {
1818 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1819 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1821 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1822 // cout << "sample: " << sample1 << endl;
1823 // cout << "sample: " << sample1 << " -> ";
1824 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1826 // if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1))))
1827 // {
1828 // cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1829 // break;
1830 // }
1832 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1833 cout << "ERROR: timecode2 not equal timecode1" << endl;
1834 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1835 cout << "sample: " << sample1 << endl;
1836 cout << "sample: " << sample1 << " -> ";
1837 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1838 break;
1840 oldsample = sample1;
1841 _session->timecode_increment_minutes( timecode1 );
1844 cout << "sample_increment: " << sample_increment << endl;
1845 cout << "sample: " << sample1 << " -> ";
1846 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1847 #endif
1849 #ifdef Timecode_SAMPLE_TEST_7
1850 // Test 7: use_offset = true, use_subframes = false, increment hours
1851 cout << "use_offset = true, use_subframes = false, increment hours" << endl;
1853 timecode1.hours = 0;
1854 timecode1.minutes = 0;
1855 timecode1.seconds = 0;
1856 timecode1.frames = 0;
1857 timecode1.subframes = 0;
1858 sample1 = oldsample = 0;
1859 sample_increment = _session->frame_rate() * 60 * 60;
1861 _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1862 cout << "Starting at sample: " << sample1 << " -> ";
1863 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1865 for (int i = 0; i < 10; i++) {
1866 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1867 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1869 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1870 // cout << "sample: " << sample1 << endl;
1871 // cout << "sample: " << sample1 << " -> ";
1872 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1874 // if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1))))
1875 // {
1876 // cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1877 // break;
1878 // }
1880 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1881 cout << "ERROR: timecode2 not equal timecode1" << endl;
1882 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1883 cout << "sample: " << sample1 << endl;
1884 cout << "sample: " << sample1 << " -> ";
1885 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1886 break;
1888 oldsample = sample1;
1889 _session->timecode_increment_hours( timecode1 );
1892 cout << "sample_increment: " << sample_increment << endl;
1893 cout << "sample: " << sample1 << " -> ";
1894 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1895 #endif
1897 #endif
1899 return sample;
1902 framepos_t
1903 AudioClock::minsec_frame_from_display () const
1905 if (_session == 0) {
1906 return 0;
1909 int hrs = atoi (ms_hours_label.get_text());
1910 int mins = atoi (ms_minutes_label.get_text());
1911 float secs = atof (ms_seconds_label.get_text());
1913 framecnt_t sr = _session->frame_rate();
1915 return (framepos_t) floor ((hrs * 60.0f * 60.0f * sr) + (mins * 60.0f * sr) + (secs * sr));
1918 framepos_t
1919 AudioClock::bbt_frame_from_display (framepos_t pos) const
1921 if (_session == 0) {
1922 error << "AudioClock::current_time() called with BBT mode but without session!" << endmsg;
1923 return 0;
1926 AnyTime any;
1927 any.type = AnyTime::BBT;
1929 any.bbt.bars = atoi (bars_label.get_text());
1930 any.bbt.beats = atoi (beats_label.get_text());
1931 any.bbt.ticks = atoi (ticks_label.get_text());
1933 if (is_duration) {
1934 any.bbt.bars++;
1935 any.bbt.beats++;
1936 return _session->any_duration_to_frames (pos, any);
1937 } else {
1938 return _session->convert_to_frames (any);
1943 framepos_t
1944 AudioClock::bbt_frame_duration_from_display (framepos_t pos) const
1946 if (_session == 0) {
1947 error << "AudioClock::current_time() called with BBT mode but without session!" << endmsg;
1948 return 0;
1951 Timecode::BBT_Time bbt;
1954 bbt.bars = atoi (bars_label.get_text());
1955 bbt.beats = atoi (beats_label.get_text());
1956 bbt.ticks = atoi (ticks_label.get_text());
1958 return _session->tempo_map().bbt_duration_at(pos,bbt,1);
1961 framepos_t
1962 AudioClock::audio_frame_from_display () const
1964 return (framepos_t) atoi (audio_frames_label.get_text());
1967 void
1968 AudioClock::build_ops_menu ()
1970 using namespace Menu_Helpers;
1971 ops_menu = new Menu;
1972 MenuList& ops_items = ops_menu->items();
1973 ops_menu->set_name ("ArdourContextMenu");
1975 if (!Profile->get_sae()) {
1976 ops_items.push_back (MenuElem (_("Timecode"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), Timecode)));
1978 ops_items.push_back (MenuElem (_("Bars:Beats"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), BBT)));
1979 ops_items.push_back (MenuElem (_("Minutes:Seconds"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), MinSec)));
1980 ops_items.push_back (MenuElem (_("Samples"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), Frames)));
1981 ops_items.push_back (MenuElem (_("Off"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), Off)));
1983 if (editable && !is_duration && !_follows_playhead) {
1984 ops_items.push_back (SeparatorElem());
1985 ops_items.push_back (MenuElem (_("Set From Playhead"), sigc::mem_fun(*this, &AudioClock::set_from_playhead)));
1986 ops_items.push_back (MenuElem (_("Locate to This Time"), sigc::mem_fun(*this, &AudioClock::locate)));
1990 void
1991 AudioClock::set_from_playhead ()
1993 if (!_session) {
1994 return;
1997 set (_session->transport_frame());
1998 ValueChanged ();
2001 void
2002 AudioClock::locate ()
2004 if (!_session || is_duration) {
2005 return;
2008 _session->request_locate (current_time(), _session->transport_rolling ());
2011 void
2012 AudioClock::set_mode (Mode m)
2014 /* slightly tricky: this is called from within the ARDOUR_UI
2015 constructor by some of its clock members. at that time
2016 the instance pointer is unset, so we have to be careful.
2017 the main idea is to drop keyboard focus in case we had
2018 started editing the clock and then we switch clock mode.
2021 clock_base.grab_focus ();
2023 if (_mode == m) {
2024 return;
2027 clock_base.remove ();
2029 _mode = m;
2031 switch (_mode) {
2032 case Timecode:
2033 clock_base.add (timecode_packer_hbox);
2034 break;
2036 case BBT:
2037 clock_base.add (bbt_packer_hbox);
2038 break;
2040 case MinSec:
2041 clock_base.add (minsec_packer_hbox);
2042 break;
2044 case Frames:
2045 clock_base.add (frames_packer_hbox);
2046 break;
2048 case Off:
2049 clock_base.add (off_hbox);
2050 break;
2053 set_size_requests ();
2055 set (last_when, true);
2056 clock_base.show_all ();
2057 key_entry_state = 0;
2059 if (!is_transient) {
2060 ModeChanged (); /* EMIT SIGNAL (the static one)*/
2063 mode_changed (); /* EMIT SIGNAL (the member one) */
2066 void
2067 AudioClock::set_size_requests ()
2069 /* note that in some fonts, "88" is narrower than "00" */
2071 switch (_mode) {
2072 case Timecode:
2073 Gtkmm2ext::set_size_request_to_display_given_text (hours_label, "-88", 5, 5);
2074 Gtkmm2ext::set_size_request_to_display_given_text (minutes_label, "88", 5, 5);
2075 Gtkmm2ext::set_size_request_to_display_given_text (seconds_label, "88", 5, 5);
2076 Gtkmm2ext::set_size_request_to_display_given_text (frames_label, "88", 5, 5);
2077 break;
2079 case BBT:
2080 Gtkmm2ext::set_size_request_to_display_given_text (bars_label, "-888", 5, 5);
2081 Gtkmm2ext::set_size_request_to_display_given_text (beats_label, "88", 5, 5);
2082 Gtkmm2ext::set_size_request_to_display_given_text (ticks_label, "8888", 5, 5);
2083 break;
2085 case MinSec:
2086 Gtkmm2ext::set_size_request_to_display_given_text (ms_hours_label, "88", 5, 5);
2087 Gtkmm2ext::set_size_request_to_display_given_text (ms_minutes_label, "88", 5, 5);
2088 Gtkmm2ext::set_size_request_to_display_given_text (ms_seconds_label, "88.888", 5, 5);
2089 break;
2091 case Frames:
2092 Gtkmm2ext::set_size_request_to_display_given_text (audio_frames_label, "8888888888", 5, 5);
2093 break;
2095 case Off:
2096 Gtkmm2ext::set_size_request_to_display_given_text (off_hbox, "00000", 5, 5);
2097 break;
2102 void
2103 AudioClock::set_bbt_reference (framepos_t pos)
2105 bbt_reference_time = pos;
2108 void
2109 AudioClock::on_style_changed (const Glib::RefPtr<Gtk::Style>& old_style)
2111 HBox::on_style_changed (old_style);
2113 /* propagate style changes to all component widgets that should inherit the main one */
2115 Glib::RefPtr<RcStyle> rcstyle = get_modifier_style();
2117 clock_base.modify_style (rcstyle);
2118 audio_frames_label.modify_style (rcstyle);
2119 hours_label.modify_style (rcstyle);
2120 minutes_label.modify_style (rcstyle);
2121 seconds_label.modify_style (rcstyle);
2122 frames_label.modify_style (rcstyle);
2123 bars_label.modify_style (rcstyle);
2124 beats_label.modify_style (rcstyle);
2125 ticks_label.modify_style (rcstyle);
2126 ms_hours_label.modify_style (rcstyle);
2127 ms_minutes_label.modify_style (rcstyle);
2128 ms_seconds_label.modify_style (rcstyle);
2129 hours_ebox.modify_style (rcstyle);
2130 minutes_ebox.modify_style (rcstyle);
2131 seconds_ebox.modify_style (rcstyle);
2132 frames_ebox.modify_style (rcstyle);
2133 audio_frames_ebox.modify_style (rcstyle);
2134 bars_ebox.modify_style (rcstyle);
2135 beats_ebox.modify_style (rcstyle);
2136 ticks_ebox.modify_style (rcstyle);
2137 ms_hours_ebox.modify_style (rcstyle);
2138 ms_minutes_ebox.modify_style (rcstyle);
2139 ms_seconds_ebox.modify_style (rcstyle);
2141 colon1.modify_style (rcstyle);
2142 colon2.modify_style (rcstyle);
2143 colon3.modify_style (rcstyle);
2144 colon4.modify_style (rcstyle);
2145 colon5.modify_style (rcstyle);
2146 b1.modify_style (rcstyle);
2147 b2.modify_style (rcstyle);
2149 set_size_requests ();
2152 void
2153 AudioClock::set_is_duration (bool yn)
2155 if (yn == is_duration) {
2156 return;
2159 is_duration = yn;
2160 set (last_when, true, 0, 's');