fix math bug with numthreads computation
[ardour2.git] / gtk2_ardour / audio_clock.cc
blobbe1bb97713b763e5d9e97cc5facda2a2e7b4ac90
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 <gtkmm2ext/utils.h>
28 #include "ardour/ardour.h"
29 #include "ardour/session.h"
30 #include "ardour/tempo.h"
31 #include "ardour/profile.h"
32 #include <sigc++/bind.h>
34 #include "ardour_ui.h"
35 #include "audio_clock.h"
36 #include "utils.h"
37 #include "keyboard.h"
38 #include "gui_thread.h"
39 #include "i18n.h"
41 using namespace ARDOUR;
42 using namespace PBD;
43 using namespace Gtk;
44 using namespace std;
46 using Gtkmm2ext::Keyboard;
48 using PBD::atoi;
49 using PBD::atof;
51 sigc::signal<void> AudioClock::ModeChanged;
52 vector<AudioClock*> AudioClock::clocks;
54 const uint32_t AudioClock::field_length[(int) AudioClock::AudioFrames+1] = {
55 2, /* Timecode_Hours */
56 2, /* Timecode_Minutes */
57 2, /* Timecode_Seconds */
58 2, /* Timecode_Frames */
59 2, /* MS_Hours */
60 2, /* MS_Minutes */
61 5, /* MS_Seconds */
62 3, /* Bars */
63 2, /* Beats */
64 4, /* Tick */
65 10 /* Audio Frame */
68 AudioClock::AudioClock (const string& clock_name, bool transient, const string& widget_name,
69 bool allow_edit, bool follows_playhead, bool duration, bool with_info)
70 : _name (clock_name),
71 is_transient (transient),
72 is_duration (duration),
73 editable (allow_edit),
74 _follows_playhead (follows_playhead),
75 colon1 (":"),
76 colon2 (":"),
77 colon3 (":"),
78 colon4 (":"),
79 colon5 (":"),
80 b1 ("|"),
81 b2 ("|"),
82 last_when(0)
84 last_when = 0;
85 last_pdelta = 0;
86 last_sdelta = 0;
87 key_entry_state = 0;
88 ops_menu = 0;
89 dragging = false;
90 bbt_reference_time = -1;
92 if (with_info) {
93 frames_upper_info_label = manage (new Label);
94 frames_lower_info_label = manage (new Label);
95 timecode_upper_info_label = manage (new Label);
96 timecode_lower_info_label = manage (new Label);
97 bbt_upper_info_label = manage (new Label);
98 bbt_lower_info_label = manage (new Label);
100 frames_upper_info_label->set_name ("AudioClockFramesUpperInfo");
101 frames_lower_info_label->set_name ("AudioClockFramesLowerInfo");
102 timecode_upper_info_label->set_name ("AudioClockTimecodeUpperInfo");
103 timecode_lower_info_label->set_name ("AudioClockTimecodeLowerInfo");
104 bbt_upper_info_label->set_name ("AudioClockBBTUpperInfo");
105 bbt_lower_info_label->set_name ("AudioClockBBTLowerInfo");
107 Gtkmm2ext::set_size_request_to_display_given_text(*timecode_upper_info_label, "23.98",0,0);
108 Gtkmm2ext::set_size_request_to_display_given_text(*timecode_lower_info_label, "NDF",0,0);
110 Gtkmm2ext::set_size_request_to_display_given_text(*bbt_upper_info_label, "88|88",0,0);
111 Gtkmm2ext::set_size_request_to_display_given_text(*bbt_lower_info_label, "888.88",0,0);
113 frames_info_box.pack_start (*frames_upper_info_label, true, true);
114 frames_info_box.pack_start (*frames_lower_info_label, true, true);
115 timecode_info_box.pack_start (*timecode_upper_info_label, true, true);
116 timecode_info_box.pack_start (*timecode_lower_info_label, true, true);
117 bbt_info_box.pack_start (*bbt_upper_info_label, true, true);
118 bbt_info_box.pack_start (*bbt_lower_info_label, true, true);
120 } else {
121 frames_upper_info_label = 0;
122 frames_lower_info_label = 0;
123 timecode_upper_info_label = 0;
124 timecode_lower_info_label = 0;
125 bbt_upper_info_label = 0;
126 bbt_lower_info_label = 0;
129 audio_frames_ebox.add (audio_frames_label);
131 frames_packer.set_homogeneous (false);
132 frames_packer.set_border_width (2);
133 frames_packer.pack_start (audio_frames_ebox, false, false);
135 if (with_info) {
136 frames_packer.pack_start (frames_info_box, false, false, 5);
139 frames_packer_hbox.pack_start (frames_packer, true, false);
141 hours_ebox.add (hours_label);
142 minutes_ebox.add (minutes_label);
143 seconds_ebox.add (seconds_label);
144 frames_ebox.add (frames_label);
145 bars_ebox.add (bars_label);
146 beats_ebox.add (beats_label);
147 ticks_ebox.add (ticks_label);
148 ms_hours_ebox.add (ms_hours_label);
149 ms_minutes_ebox.add (ms_minutes_label);
150 ms_seconds_ebox.add (ms_seconds_label);
152 timecode_packer.set_homogeneous (false);
153 timecode_packer.set_border_width (2);
154 timecode_packer.pack_start (hours_ebox, false, false);
155 timecode_packer.pack_start (colon1, false, false);
156 timecode_packer.pack_start (minutes_ebox, false, false);
157 timecode_packer.pack_start (colon2, false, false);
158 timecode_packer.pack_start (seconds_ebox, false, false);
159 timecode_packer.pack_start (colon3, false, false);
160 timecode_packer.pack_start (frames_ebox, false, false);
162 if (with_info) {
163 timecode_packer.pack_start (timecode_info_box, false, false, 5);
166 timecode_packer_hbox.pack_start (timecode_packer, true, false);
168 bbt_packer.set_homogeneous (false);
169 bbt_packer.set_border_width (2);
170 bbt_packer.pack_start (bars_ebox, false, false);
171 bbt_packer.pack_start (b1, false, false);
172 bbt_packer.pack_start (beats_ebox, false, false);
173 bbt_packer.pack_start (b2, false, false);
174 bbt_packer.pack_start (ticks_ebox, false, false);
176 if (with_info) {
177 bbt_packer.pack_start (bbt_info_box, false, false, 5);
180 bbt_packer_hbox.pack_start (bbt_packer, true, false);
182 minsec_packer.set_homogeneous (false);
183 minsec_packer.set_border_width (2);
184 minsec_packer.pack_start (ms_hours_ebox, false, false);
185 minsec_packer.pack_start (colon4, false, false);
186 minsec_packer.pack_start (ms_minutes_ebox, false, false);
187 minsec_packer.pack_start (colon5, false, false);
188 minsec_packer.pack_start (ms_seconds_ebox, false, false);
190 minsec_packer_hbox.pack_start (minsec_packer, true, false);
192 clock_frame.set_shadow_type (Gtk::SHADOW_IN);
193 clock_frame.set_name ("BaseFrame");
195 clock_frame.add (clock_base);
197 set_widget_name (widget_name);
199 _mode = BBT; /* lie to force mode switch */
200 set_mode (Timecode);
202 pack_start (clock_frame, true, true);
204 /* the clock base handles button releases for menu popup regardless of
205 editable status. if the clock is editable, the clock base is where
206 we pass focus to after leaving the last editable "field", which
207 will then shutdown editing till the user starts it up again.
209 it does this because the focus out event on the field disables
210 keyboard event handling, and we don't connect anything up to
211 notice focus in on the clock base. hence, keyboard event handling
212 stays disabled.
215 clock_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::SCROLL_MASK);
216 clock_base.signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &AudioClock::field_button_release_event), Timecode_Hours));
218 Session::TimecodeOffsetChanged.connect (_session_connections, invalidator (*this), boost::bind (&AudioClock::timecode_offset_changed, this), gui_context());
220 if (editable) {
221 setup_events ();
224 set (last_when, true);
226 if (!is_transient) {
227 clocks.push_back (this);
231 void
232 AudioClock::set_widget_name (string name)
234 Widget::set_name (name);
236 clock_base.set_name (name);
238 audio_frames_label.set_name (name);
239 hours_label.set_name (name);
240 minutes_label.set_name (name);
241 seconds_label.set_name (name);
242 frames_label.set_name (name);
243 bars_label.set_name (name);
244 beats_label.set_name (name);
245 ticks_label.set_name (name);
246 ms_hours_label.set_name (name);
247 ms_minutes_label.set_name (name);
248 ms_seconds_label.set_name (name);
249 hours_ebox.set_name (name);
250 minutes_ebox.set_name (name);
251 seconds_ebox.set_name (name);
252 frames_ebox.set_name (name);
253 audio_frames_ebox.set_name (name);
254 bars_ebox.set_name (name);
255 beats_ebox.set_name (name);
256 ticks_ebox.set_name (name);
257 ms_hours_ebox.set_name (name);
258 ms_minutes_ebox.set_name (name);
259 ms_seconds_ebox.set_name (name);
261 colon1.set_name (name);
262 colon2.set_name (name);
263 colon3.set_name (name);
264 colon4.set_name (name);
265 colon5.set_name (name);
266 b1.set_name (name);
267 b2.set_name (name);
269 queue_draw ();
272 void
273 AudioClock::setup_events ()
275 clock_base.set_flags (Gtk::CAN_FOCUS);
277 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);
278 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);
279 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);
280 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);
281 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);
282 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);
283 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);
284 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);
285 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);
286 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);
287 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);
289 hours_ebox.set_flags (Gtk::CAN_FOCUS);
290 minutes_ebox.set_flags (Gtk::CAN_FOCUS);
291 seconds_ebox.set_flags (Gtk::CAN_FOCUS);
292 frames_ebox.set_flags (Gtk::CAN_FOCUS);
293 audio_frames_ebox.set_flags (Gtk::CAN_FOCUS);
294 bars_ebox.set_flags (Gtk::CAN_FOCUS);
295 beats_ebox.set_flags (Gtk::CAN_FOCUS);
296 ticks_ebox.set_flags (Gtk::CAN_FOCUS);
297 ms_hours_ebox.set_flags (Gtk::CAN_FOCUS);
298 ms_minutes_ebox.set_flags (Gtk::CAN_FOCUS);
299 ms_seconds_ebox.set_flags (Gtk::CAN_FOCUS);
301 hours_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), Timecode_Hours));
302 minutes_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), Timecode_Minutes));
303 seconds_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), Timecode_Seconds));
304 frames_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), Timecode_Frames));
305 audio_frames_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), AudioFrames));
306 bars_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), Bars));
307 beats_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), Beats));
308 ticks_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), Ticks));
309 ms_hours_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), MS_Hours));
310 ms_minutes_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), MS_Minutes));
311 ms_seconds_ebox.signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_motion_notify_event), MS_Seconds));
313 hours_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), Timecode_Hours));
314 minutes_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), Timecode_Minutes));
315 seconds_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), Timecode_Seconds));
316 frames_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), Timecode_Frames));
317 audio_frames_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), AudioFrames));
318 bars_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), Bars));
319 beats_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), Beats));
320 ticks_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), Ticks));
321 ms_hours_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), MS_Hours));
322 ms_minutes_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), MS_Minutes));
323 ms_seconds_ebox.signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_press_event), MS_Seconds));
325 hours_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), Timecode_Hours));
326 minutes_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), Timecode_Minutes));
327 seconds_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), Timecode_Seconds));
328 frames_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), Timecode_Frames));
329 audio_frames_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), AudioFrames));
330 bars_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), Bars));
331 beats_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), Beats));
332 ticks_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), Ticks));
333 ms_hours_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), MS_Hours));
334 ms_minutes_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), MS_Minutes));
335 ms_seconds_ebox.signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_release_event), MS_Seconds));
337 hours_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), Timecode_Hours));
338 minutes_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), Timecode_Minutes));
339 seconds_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), Timecode_Seconds));
340 frames_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), Timecode_Frames));
341 audio_frames_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), AudioFrames));
342 bars_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), Bars));
343 beats_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), Beats));
344 ticks_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), Ticks));
345 ms_hours_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), MS_Hours));
346 ms_minutes_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), MS_Minutes));
347 ms_seconds_ebox.signal_scroll_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_button_scroll_event), MS_Seconds));
349 hours_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), Timecode_Hours));
350 minutes_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), Timecode_Minutes));
351 seconds_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), Timecode_Seconds));
352 frames_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), Timecode_Frames));
353 audio_frames_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), AudioFrames));
354 bars_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), Bars));
355 beats_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), Beats));
356 ticks_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), Ticks));
357 ms_hours_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), MS_Hours));
358 ms_minutes_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), MS_Minutes));
359 ms_seconds_ebox.signal_key_press_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_press_event), MS_Seconds));
361 hours_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), Timecode_Hours));
362 minutes_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), Timecode_Minutes));
363 seconds_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), Timecode_Seconds));
364 frames_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), Timecode_Frames));
365 audio_frames_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), AudioFrames));
366 bars_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), Bars));
367 beats_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), Beats));
368 ticks_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), Ticks));
369 ms_hours_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), MS_Hours));
370 ms_minutes_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), MS_Minutes));
371 ms_seconds_ebox.signal_key_release_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_key_release_event), MS_Seconds));
373 hours_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), Timecode_Hours));
374 minutes_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), Timecode_Minutes));
375 seconds_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), Timecode_Seconds));
376 frames_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), Timecode_Frames));
377 audio_frames_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), AudioFrames));
378 bars_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), Bars));
379 beats_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), Beats));
380 ticks_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), Ticks));
381 ms_hours_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), MS_Hours));
382 ms_minutes_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), MS_Minutes));
383 ms_seconds_ebox.signal_focus_in_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_in_event), MS_Seconds));
385 hours_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), Timecode_Hours));
386 minutes_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), Timecode_Minutes));
387 seconds_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), Timecode_Seconds));
388 frames_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), Timecode_Frames));
389 audio_frames_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), AudioFrames));
390 bars_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), Bars));
391 beats_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), Beats));
392 ticks_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), Ticks));
393 ms_hours_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), MS_Hours));
394 ms_minutes_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), MS_Minutes));
395 ms_seconds_ebox.signal_focus_out_event().connect (sigc::bind (sigc::mem_fun(*this, &AudioClock::field_focus_out_event), MS_Seconds));
397 clock_base.signal_focus_in_event().connect (sigc::mem_fun (*this, &AudioClock::drop_focus_handler));
400 bool
401 AudioClock::drop_focus_handler (GdkEventFocus*)
403 Keyboard::magic_widget_drop_focus ();
404 return false;
407 void
408 AudioClock::on_realize ()
410 HBox::on_realize ();
412 /* styles are not available until the widgets are bound to a window */
414 set_size_requests ();
417 void
418 AudioClock::set (nframes_t when, bool force, nframes_t offset, char which)
421 if ((!force && !is_visible()) || _session == 0) {
422 return;
425 if (when == last_when && !offset && !force) {
426 return;
429 bool pdelta = Config->get_primary_clock_delta_edit_cursor();
430 bool sdelta = Config->get_secondary_clock_delta_edit_cursor();
432 if (offset && which == 'p' && pdelta) {
433 when = (when > offset) ? when - offset : offset - when;
434 } else if (offset && which == 's' && sdelta) {
435 when = (when > offset) ? when - offset : offset - when;
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;
476 void
477 AudioClock::timecode_offset_changed ()
479 nframes_t current;
481 switch (_mode) {
482 case Timecode:
483 if (is_duration) {
484 current = current_duration();
485 } else {
486 current = current_time ();
488 set (current, true);
489 break;
490 default:
491 break;
495 void
496 AudioClock::set_frames (nframes_t when, bool /*force*/)
498 char buf[32];
499 snprintf (buf, sizeof (buf), "%u", when);
500 audio_frames_label.set_text (buf);
502 if (frames_upper_info_label) {
503 nframes_t rate = _session->frame_rate();
505 if (fmod (rate, 1000.0) == 0.000) {
506 sprintf (buf, "%uK", rate/1000);
507 } else {
508 sprintf (buf, "%.3fK", rate/1000.0f);
511 if (frames_upper_info_label->get_text() != buf) {
512 frames_upper_info_label->set_text (buf);
515 float vid_pullup = _session->config.get_video_pullup();
517 if (vid_pullup == 0.0) {
518 if (frames_lower_info_label->get_text () != _("none")) {
519 frames_lower_info_label->set_text(_("none"));
521 } else {
522 sprintf (buf, "%-6.4f", vid_pullup);
523 if (frames_lower_info_label->get_text() != buf) {
524 frames_lower_info_label->set_text (buf);
530 void
531 AudioClock::set_minsec (nframes_t when, bool force)
533 char buf[32];
534 nframes_t left;
535 int hrs;
536 int mins;
537 float secs;
539 left = when;
540 hrs = (int) floor (left / (_session->frame_rate() * 60.0f * 60.0f));
541 left -= (nframes_t) floor (hrs * _session->frame_rate() * 60.0f * 60.0f);
542 mins = (int) floor (left / (_session->frame_rate() * 60.0f));
543 left -= (nframes_t) floor (mins * _session->frame_rate() * 60.0f);
544 secs = left / (float) _session->frame_rate();
546 if (force || hrs != ms_last_hrs) {
547 sprintf (buf, "%02d", hrs);
548 ms_hours_label.set_text (buf);
549 ms_last_hrs = hrs;
552 if (force || mins != ms_last_mins) {
553 sprintf (buf, "%02d", mins);
554 ms_minutes_label.set_text (buf);
555 ms_last_mins = mins;
558 if (force || secs != ms_last_secs) {
559 sprintf (buf, "%06.3f", secs);
560 ms_seconds_label.set_text (buf);
561 ms_last_secs = secs;
565 void
566 AudioClock::set_timecode (nframes_t when, bool force)
568 char buf[32];
569 Timecode::Time timecode;
571 if (is_duration) {
572 _session->timecode_duration (when, timecode);
573 } else {
574 _session->timecode_time (when, timecode);
577 if (force || timecode.hours != last_hrs || timecode.negative != last_negative) {
578 if (timecode.negative) {
579 sprintf (buf, "-%02" PRIu32, timecode.hours);
580 } else {
581 sprintf (buf, " %02" PRIu32, timecode.hours);
583 hours_label.set_text (buf);
584 last_hrs = timecode.hours;
585 last_negative = timecode.negative;
588 if (force || timecode.minutes != last_mins) {
589 sprintf (buf, "%02" PRIu32, timecode.minutes);
590 minutes_label.set_text (buf);
591 last_mins = timecode.minutes;
594 if (force || timecode.seconds != last_secs) {
595 sprintf (buf, "%02" PRIu32, timecode.seconds);
596 seconds_label.set_text (buf);
597 last_secs = timecode.seconds;
600 if (force || timecode.frames != last_frames) {
601 sprintf (buf, "%02" PRIu32, timecode.frames);
602 frames_label.set_text (buf);
603 last_frames = timecode.frames;
606 if (timecode_upper_info_label) {
607 double timecode_frames = _session->timecode_frames_per_second();
609 if ( fmod(timecode_frames, 1.0) == 0.0) {
610 sprintf (buf, "%u", int (timecode_frames));
611 } else {
612 sprintf (buf, "%.2f", timecode_frames);
615 if (timecode_upper_info_label->get_text() != buf) {
616 timecode_upper_info_label->set_text (buf);
619 if ((fabs(timecode_frames - 29.97) < 0.0001) || timecode_frames == 30) {
620 if (_session->timecode_drop_frames()) {
621 sprintf (buf, "DF");
622 } else {
623 sprintf (buf, "NDF");
625 } else {
626 // there is no drop frame alternative
627 buf[0] = '\0';
630 if (timecode_lower_info_label->get_text() != buf) {
631 timecode_lower_info_label->set_text (buf);
636 void
637 AudioClock::set_bbt (nframes_t when, bool force)
639 char buf[16];
640 BBT_Time bbt;
642 /* handle a common case */
643 if (is_duration) {
644 if (when == 0) {
645 bbt.bars = 0;
646 bbt.beats = 0;
647 bbt.ticks = 0;
648 } else {
649 _session->tempo_map().bbt_time (when, bbt);
650 bbt.bars--;
651 bbt.beats--;
653 } else {
654 _session->tempo_map().bbt_time (when, bbt);
657 sprintf (buf, "%03" PRIu32, bbt.bars);
658 if (force || bars_label.get_text () != buf) {
659 bars_label.set_text (buf);
661 sprintf (buf, "%02" PRIu32, bbt.beats);
662 if (force || beats_label.get_text () != buf) {
663 beats_label.set_text (buf);
665 sprintf (buf, "%04" PRIu32, bbt.ticks);
666 if (force || ticks_label.get_text () != buf) {
667 ticks_label.set_text (buf);
670 if (bbt_upper_info_label) {
671 nframes64_t pos;
673 if (bbt_reference_time < 0) {
674 pos = when;
675 } else {
676 pos = bbt_reference_time;
679 TempoMetric m (_session->tempo_map().metric_at (pos));
681 sprintf (buf, "%-5.2f", m.tempo().beats_per_minute());
682 if (bbt_lower_info_label->get_text() != buf) {
683 bbt_lower_info_label->set_text (buf);
685 sprintf (buf, "%g|%g", m.meter().beats_per_bar(), m.meter().note_divisor());
686 if (bbt_upper_info_label->get_text() != buf) {
687 bbt_upper_info_label->set_text (buf);
692 void
693 AudioClock::set_session (Session *s)
695 SessionHandlePtr::set_session (s);
697 if (_session) {
699 XMLProperty* prop;
700 XMLNode* node = _session->extra_xml (X_("ClockModes"));
701 AudioClock::Mode amode;
703 if (node) {
704 if ((prop = node->property (_name)) != 0) {
705 amode = AudioClock::Mode (string_2_enum (prop->value(), amode));
706 set_mode (amode);
710 set (last_when, true);
714 void
715 AudioClock::focus ()
717 switch (_mode) {
718 case Timecode:
719 hours_ebox.grab_focus ();
720 break;
722 case BBT:
723 bars_ebox.grab_focus ();
724 break;
726 case MinSec:
727 ms_hours_ebox.grab_focus ();
728 break;
730 case Frames:
731 frames_ebox.grab_focus ();
732 break;
734 case Off:
735 break;
740 bool
741 AudioClock::field_key_press_event (GdkEventKey */*ev*/, Field /*field*/)
743 /* all key activity is handled on key release */
744 return true;
747 bool
748 AudioClock::field_key_release_event (GdkEventKey *ev, Field field)
750 Label *label = 0;
751 string new_text;
752 char new_char = 0;
753 bool move_on = false;
755 switch (field) {
756 case Timecode_Hours:
757 label = &hours_label;
758 break;
759 case Timecode_Minutes:
760 label = &minutes_label;
761 break;
762 case Timecode_Seconds:
763 label = &seconds_label;
764 break;
765 case Timecode_Frames:
766 label = &frames_label;
767 break;
769 case AudioFrames:
770 label = &audio_frames_label;
771 break;
773 case MS_Hours:
774 label = &ms_hours_label;
775 break;
776 case MS_Minutes:
777 label = &ms_minutes_label;
778 break;
779 case MS_Seconds:
780 label = &ms_seconds_label;
781 break;
783 case Bars:
784 label = &bars_label;
785 break;
786 case Beats:
787 label = &beats_label;
788 break;
789 case Ticks:
790 label = &ticks_label;
791 break;
792 default:
793 return false;
796 switch (ev->keyval) {
797 case GDK_0:
798 case GDK_KP_0:
799 new_char = '0';
800 break;
801 case GDK_1:
802 case GDK_KP_1:
803 new_char = '1';
804 break;
805 case GDK_2:
806 case GDK_KP_2:
807 new_char = '2';
808 break;
809 case GDK_3:
810 case GDK_KP_3:
811 new_char = '3';
812 break;
813 case GDK_4:
814 case GDK_KP_4:
815 new_char = '4';
816 break;
817 case GDK_5:
818 case GDK_KP_5:
819 new_char = '5';
820 break;
821 case GDK_6:
822 case GDK_KP_6:
823 new_char = '6';
824 break;
825 case GDK_7:
826 case GDK_KP_7:
827 new_char = '7';
828 break;
829 case GDK_8:
830 case GDK_KP_8:
831 new_char = '8';
832 break;
833 case GDK_9:
834 case GDK_KP_9:
835 new_char = '9';
836 break;
838 case GDK_period:
839 case GDK_KP_Decimal:
840 if (_mode == MinSec && field == MS_Seconds) {
841 new_char = '.';
842 } else {
843 return false;
845 break;
847 case GDK_Tab:
848 case GDK_Return:
849 case GDK_KP_Enter:
850 move_on = true;
851 break;
853 case GDK_Escape:
854 key_entry_state = 0;
855 clock_base.grab_focus ();
856 ChangeAborted(); /* EMIT SIGNAL */
857 return true;
859 default:
860 return false;
863 if (!move_on) {
865 if (key_entry_state == 0) {
867 /* initialize with a fresh new string */
869 if (field != AudioFrames) {
870 for (uint32_t xn = 0; xn < field_length[field] - 1; ++xn) {
871 new_text += '0';
873 } else {
874 new_text = "";
877 } else {
879 string existing = label->get_text();
880 if (existing.length() >= field_length[field]) {
881 new_text = existing.substr (1, field_length[field] - 1);
882 } else {
883 new_text = existing.substr (0, field_length[field] - 1);
887 new_text += new_char;
888 label->set_text (new_text);
889 key_entry_state++;
892 if (key_entry_state == field_length[field]) {
893 move_on = true;
896 if (move_on) {
898 if (key_entry_state) {
900 switch (field) {
901 case Timecode_Hours:
902 case Timecode_Minutes:
903 case Timecode_Seconds:
904 case Timecode_Frames:
905 // Check Timecode fields for sanity (may also adjust fields)
906 timecode_sanitize_display();
907 break;
908 case Bars:
909 case Beats:
910 case Ticks:
911 // Bars should never be, unless this clock is for a duration
912 if (atoi(bars_label.get_text()) == 0 && !is_duration) {
913 bars_label.set_text("001");
915 // beats should never be 0, unless this clock is for a duration
916 if (atoi(beats_label.get_text()) == 0 && !is_duration) {
917 beats_label.set_text("01");
919 break;
920 default:
921 break;
924 ValueChanged(); /* EMIT_SIGNAL */
927 /* move on to the next field.
930 switch (field) {
932 /* Timecode */
934 case Timecode_Hours:
935 minutes_ebox.grab_focus ();
936 break;
937 case Timecode_Minutes:
938 seconds_ebox.grab_focus ();
939 break;
940 case Timecode_Seconds:
941 frames_ebox.grab_focus ();
942 break;
943 case Timecode_Frames:
944 clock_base.grab_focus ();
945 break;
947 /* audio frames */
948 case AudioFrames:
949 clock_base.grab_focus ();
950 break;
952 /* Min:Sec */
954 case MS_Hours:
955 ms_minutes_ebox.grab_focus ();
956 break;
957 case MS_Minutes:
958 ms_seconds_ebox.grab_focus ();
959 break;
960 case MS_Seconds:
961 clock_base.grab_focus ();
962 break;
964 /* BBT */
966 case Bars:
967 beats_ebox.grab_focus ();
968 break;
969 case Beats:
970 ticks_ebox.grab_focus ();
971 break;
972 case Ticks:
973 clock_base.grab_focus ();
974 break;
976 default:
977 break;
982 //if user hit Enter, lose focus
983 switch (ev->keyval) {
984 case GDK_Return:
985 case GDK_KP_Enter:
986 clock_base.grab_focus ();
989 return true;
992 bool
993 AudioClock::field_focus_in_event (GdkEventFocus */*ev*/, Field field)
995 key_entry_state = 0;
997 Keyboard::magic_widget_grab_focus ();
999 switch (field) {
1000 case Timecode_Hours:
1001 hours_ebox.set_flags (Gtk::HAS_FOCUS);
1002 hours_ebox.set_state (Gtk::STATE_ACTIVE);
1003 break;
1004 case Timecode_Minutes:
1005 minutes_ebox.set_flags (Gtk::HAS_FOCUS);
1006 minutes_ebox.set_state (Gtk::STATE_ACTIVE);
1007 break;
1008 case Timecode_Seconds:
1009 seconds_ebox.set_flags (Gtk::HAS_FOCUS);
1010 seconds_ebox.set_state (Gtk::STATE_ACTIVE);
1011 break;
1012 case Timecode_Frames:
1013 frames_ebox.set_flags (Gtk::HAS_FOCUS);
1014 frames_ebox.set_state (Gtk::STATE_ACTIVE);
1015 break;
1017 case AudioFrames:
1018 audio_frames_ebox.set_flags (Gtk::HAS_FOCUS);
1019 audio_frames_ebox.set_state (Gtk::STATE_ACTIVE);
1020 break;
1022 case MS_Hours:
1023 ms_hours_ebox.set_flags (Gtk::HAS_FOCUS);
1024 ms_hours_ebox.set_state (Gtk::STATE_ACTIVE);
1025 break;
1026 case MS_Minutes:
1027 ms_minutes_ebox.set_flags (Gtk::HAS_FOCUS);
1028 ms_minutes_ebox.set_state (Gtk::STATE_ACTIVE);
1029 break;
1030 case MS_Seconds:
1031 ms_seconds_ebox.set_flags (Gtk::HAS_FOCUS);
1032 ms_seconds_ebox.set_state (Gtk::STATE_ACTIVE);
1033 break;
1034 case Bars:
1035 bars_ebox.set_flags (Gtk::HAS_FOCUS);
1036 bars_ebox.set_state (Gtk::STATE_ACTIVE);
1037 break;
1038 case Beats:
1039 beats_ebox.set_flags (Gtk::HAS_FOCUS);
1040 beats_ebox.set_state (Gtk::STATE_ACTIVE);
1041 break;
1042 case Ticks:
1043 ticks_ebox.set_flags (Gtk::HAS_FOCUS);
1044 ticks_ebox.set_state (Gtk::STATE_ACTIVE);
1045 break;
1048 return false;
1051 bool
1052 AudioClock::field_focus_out_event (GdkEventFocus */*ev*/, Field field)
1054 switch (field) {
1056 case Timecode_Hours:
1057 hours_ebox.unset_flags (Gtk::HAS_FOCUS);
1058 hours_ebox.set_state (Gtk::STATE_NORMAL);
1059 break;
1060 case Timecode_Minutes:
1061 minutes_ebox.unset_flags (Gtk::HAS_FOCUS);
1062 minutes_ebox.set_state (Gtk::STATE_NORMAL);
1063 break;
1064 case Timecode_Seconds:
1065 seconds_ebox.unset_flags (Gtk::HAS_FOCUS);
1066 seconds_ebox.set_state (Gtk::STATE_NORMAL);
1067 break;
1068 case Timecode_Frames:
1069 frames_ebox.unset_flags (Gtk::HAS_FOCUS);
1070 frames_ebox.set_state (Gtk::STATE_NORMAL);
1071 break;
1073 case AudioFrames:
1074 audio_frames_ebox.unset_flags (Gtk::HAS_FOCUS);
1075 audio_frames_ebox.set_state (Gtk::STATE_NORMAL);
1076 break;
1078 case MS_Hours:
1079 ms_hours_ebox.unset_flags (Gtk::HAS_FOCUS);
1080 ms_hours_ebox.set_state (Gtk::STATE_NORMAL);
1081 break;
1082 case MS_Minutes:
1083 ms_minutes_ebox.unset_flags (Gtk::HAS_FOCUS);
1084 ms_minutes_ebox.set_state (Gtk::STATE_NORMAL);
1085 break;
1086 case MS_Seconds:
1087 ms_seconds_ebox.unset_flags (Gtk::HAS_FOCUS);
1088 ms_seconds_ebox.set_state (Gtk::STATE_NORMAL);
1089 break;
1091 case Bars:
1092 bars_ebox.unset_flags (Gtk::HAS_FOCUS);
1093 bars_ebox.set_state (Gtk::STATE_NORMAL);
1094 break;
1095 case Beats:
1096 beats_ebox.unset_flags (Gtk::HAS_FOCUS);
1097 beats_ebox.set_state (Gtk::STATE_NORMAL);
1098 break;
1099 case Ticks:
1100 ticks_ebox.unset_flags (Gtk::HAS_FOCUS);
1101 ticks_ebox.set_state (Gtk::STATE_NORMAL);
1102 break;
1105 Keyboard::magic_widget_drop_focus ();
1107 return false;
1110 bool
1111 AudioClock::field_button_release_event (GdkEventButton *ev, Field field)
1113 if (dragging) {
1114 cerr << "button event on clock but we are dragging\n";
1115 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1116 dragging = false;
1117 if (ev->y > drag_start_y+1 || ev->y < drag_start_y-1 || Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)){
1118 // we actually dragged so return without setting editing focus, or we shift clicked
1119 return true;
1123 if (!editable) {
1124 if (ops_menu == 0) {
1125 build_ops_menu ();
1127 ops_menu->popup (1, ev->time);
1128 return true;
1131 if (Keyboard::is_context_menu_event (ev)) {
1132 cerr << "Context menu event on clock\n";
1133 if (ops_menu == 0) {
1134 build_ops_menu ();
1136 ops_menu->popup (1, ev->time);
1137 return true;
1140 switch (ev->button) {
1141 case 1:
1142 switch (field) {
1143 case Timecode_Hours:
1144 hours_ebox.grab_focus();
1145 break;
1146 case Timecode_Minutes:
1147 minutes_ebox.grab_focus();
1148 break;
1149 case Timecode_Seconds:
1150 seconds_ebox.grab_focus();
1151 break;
1152 case Timecode_Frames:
1153 frames_ebox.grab_focus();
1154 break;
1156 case AudioFrames:
1157 audio_frames_ebox.grab_focus();
1158 break;
1160 case MS_Hours:
1161 ms_hours_ebox.grab_focus();
1162 break;
1163 case MS_Minutes:
1164 ms_minutes_ebox.grab_focus();
1165 break;
1166 case MS_Seconds:
1167 ms_seconds_ebox.grab_focus();
1168 break;
1170 case Bars:
1171 bars_ebox.grab_focus ();
1172 break;
1173 case Beats:
1174 beats_ebox.grab_focus ();
1175 break;
1176 case Ticks:
1177 ticks_ebox.grab_focus ();
1178 break;
1180 break;
1182 default:
1183 break;
1186 return true;
1189 bool
1190 AudioClock::field_button_press_event (GdkEventButton *ev, Field /*field*/)
1192 if (_session == 0) {
1193 return false;
1196 nframes_t frames = 0;
1198 switch (ev->button) {
1199 case 1:
1200 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
1201 set (frames, true);
1202 ValueChanged (); /* EMIT_SIGNAL */
1205 /* make absolutely sure that the pointer is grabbed */
1206 gdk_pointer_grab(ev->window,false ,
1207 GdkEventMask( Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK |Gdk::BUTTON_RELEASE_MASK),
1208 NULL,NULL,ev->time);
1209 dragging = true;
1210 drag_accum = 0;
1211 drag_start_y = ev->y;
1212 drag_y = ev->y;
1213 break;
1215 case 2:
1216 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
1217 set (frames, true);
1218 ValueChanged (); /* EMIT_SIGNAL */
1220 break;
1222 case 3:
1223 /* used for context sensitive menu */
1224 return false;
1225 break;
1227 default:
1228 return false;
1229 break;
1232 return true;
1235 bool
1236 AudioClock::field_button_scroll_event (GdkEventScroll *ev, Field field)
1238 if (_session == 0) {
1239 return false;
1242 nframes_t frames = 0;
1244 switch (ev->direction) {
1246 case GDK_SCROLL_UP:
1247 frames = get_frames (field);
1248 if (frames != 0) {
1249 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1250 frames *= 10;
1252 set (current_time() + frames, true);
1253 ValueChanged (); /* EMIT_SIGNAL */
1255 break;
1257 case GDK_SCROLL_DOWN:
1258 frames = get_frames (field);
1259 if (frames != 0) {
1260 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1261 frames *= 10;
1264 if ((double)current_time() - (double)frames < 0.0) {
1265 set (0, true);
1266 } else {
1267 set (current_time() - frames, true);
1270 ValueChanged (); /* EMIT_SIGNAL */
1272 break;
1274 default:
1275 return false;
1276 break;
1279 return true;
1282 bool
1283 AudioClock::field_motion_notify_event (GdkEventMotion *ev, Field field)
1285 if (_session == 0 || !dragging) {
1286 return false;
1289 float pixel_frame_scale_factor = 0.2f;
1292 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1293 pixel_frame_scale_factor = 0.1f;
1297 if (Keyboard::modifier_state_contains (ev->state,
1298 Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)) {
1300 pixel_frame_scale_factor = 0.025f;
1303 double y_delta = ev->y - drag_y;
1305 drag_accum += y_delta*pixel_frame_scale_factor;
1307 drag_y = ev->y;
1309 if (trunc(drag_accum) != 0) {
1311 nframes_t frames;
1312 nframes_t pos ;
1313 int dir;
1314 dir = (drag_accum < 0 ? 1:-1);
1315 pos = current_time();
1316 frames = get_frames (field,pos,dir);
1318 if (frames != 0 && frames * drag_accum < current_time()) {
1320 set ((nframes_t) floor (pos - drag_accum * frames), false); // minus because up is negative in computer-land
1322 } else {
1323 set (0 , false);
1327 drag_accum= 0;
1328 ValueChanged(); /* EMIT_SIGNAL */
1333 return true;
1336 nframes_t
1337 AudioClock::get_frames (Field field,nframes_t pos,int dir)
1340 nframes_t frames = 0;
1341 BBT_Time bbt;
1342 switch (field) {
1343 case Timecode_Hours:
1344 frames = (nframes_t) floor (3600.0 * _session->frame_rate());
1345 break;
1346 case Timecode_Minutes:
1347 frames = (nframes_t) floor (60.0 * _session->frame_rate());
1348 break;
1349 case Timecode_Seconds:
1350 frames = _session->frame_rate();
1351 break;
1352 case Timecode_Frames:
1353 frames = (nframes_t) floor (_session->frame_rate() / _session->timecode_frames_per_second());
1354 break;
1356 case AudioFrames:
1357 frames = 1;
1358 break;
1360 case MS_Hours:
1361 frames = (nframes_t) floor (3600.0 * _session->frame_rate());
1362 break;
1363 case MS_Minutes:
1364 frames = (nframes_t) floor (60.0 * _session->frame_rate());
1365 break;
1366 case MS_Seconds:
1367 frames = _session->frame_rate();
1368 break;
1370 case Bars:
1371 bbt.bars = 1;
1372 bbt.beats = 0;
1373 bbt.ticks = 0;
1374 frames = _session->tempo_map().bbt_duration_at(pos,bbt,dir);
1375 break;
1376 case Beats:
1377 bbt.bars = 0;
1378 bbt.beats = 1;
1379 bbt.ticks = 0;
1380 frames = _session->tempo_map().bbt_duration_at(pos,bbt,dir);
1381 break;
1382 case Ticks:
1383 bbt.bars = 0;
1384 bbt.beats = 0;
1385 bbt.ticks = 1;
1386 frames = _session->tempo_map().bbt_duration_at(pos,bbt,dir);
1387 break;
1390 return frames;
1393 nframes_t
1394 AudioClock::current_time (nframes_t pos) const
1396 nframes_t ret = 0;
1398 switch (_mode) {
1399 case Timecode:
1400 ret = timecode_frame_from_display ();
1401 break;
1402 case BBT:
1403 ret = bbt_frame_from_display (pos);
1404 break;
1406 case MinSec:
1407 ret = minsec_frame_from_display ();
1408 break;
1410 case Frames:
1411 ret = audio_frame_from_display ();
1412 break;
1414 case Off:
1415 break;
1418 return ret;
1421 nframes_t
1422 AudioClock::current_duration (nframes_t pos) const
1424 nframes_t ret = 0;
1426 switch (_mode) {
1427 case Timecode:
1428 ret = timecode_frame_from_display ();
1429 break;
1430 case BBT:
1431 ret = bbt_frame_duration_from_display (pos);
1432 break;
1434 case MinSec:
1435 ret = minsec_frame_from_display ();
1436 break;
1438 case Frames:
1439 ret = audio_frame_from_display ();
1440 break;
1442 case Off:
1443 break;
1446 return ret;
1449 void
1450 AudioClock::timecode_sanitize_display()
1452 // Check Timecode fields for sanity, possibly adjusting values
1453 if (atoi(minutes_label.get_text()) > 59) {
1454 minutes_label.set_text("59");
1457 if (atoi(seconds_label.get_text()) > 59) {
1458 seconds_label.set_text("59");
1461 switch ((long)rint(_session->timecode_frames_per_second())) {
1462 case 24:
1463 if (atoi(frames_label.get_text()) > 23) {
1464 frames_label.set_text("23");
1466 break;
1467 case 25:
1468 if (atoi(frames_label.get_text()) > 24) {
1469 frames_label.set_text("24");
1471 break;
1472 case 30:
1473 if (atoi(frames_label.get_text()) > 29) {
1474 frames_label.set_text("29");
1476 break;
1477 default:
1478 break;
1481 if (_session->timecode_drop_frames()) {
1482 if ((atoi(minutes_label.get_text()) % 10) && (atoi(seconds_label.get_text()) == 0) && (atoi(frames_label.get_text()) < 2)) {
1483 frames_label.set_text("02");
1488 nframes_t
1489 AudioClock::timecode_frame_from_display () const
1491 if (_session == 0) {
1492 return 0;
1495 Timecode::Time timecode;
1496 nframes_t sample;
1498 timecode.hours = atoi (hours_label.get_text());
1499 timecode.minutes = atoi (minutes_label.get_text());
1500 timecode.seconds = atoi (seconds_label.get_text());
1501 timecode.frames = atoi (frames_label.get_text());
1502 timecode.rate = _session->timecode_frames_per_second();
1503 timecode.drop= _session->timecode_drop_frames();
1505 _session->timecode_to_sample( timecode, sample, false /* use_offset */, false /* use_subframes */ );
1508 #if 0
1509 #define Timecode_SAMPLE_TEST_1
1510 #define Timecode_SAMPLE_TEST_2
1511 #define Timecode_SAMPLE_TEST_3
1512 #define Timecode_SAMPLE_TEST_4
1513 #define Timecode_SAMPLE_TEST_5
1514 #define Timecode_SAMPLE_TEST_6
1515 #define Timecode_SAMPLE_TEST_7
1517 // Testcode for timecode<->sample conversions (P.S.)
1518 Timecode::Time timecode1;
1519 nframes_t sample1;
1520 nframes_t oldsample = 0;
1521 Timecode::Time timecode2;
1522 nframes_t sample_increment;
1524 sample_increment = (long)rint(_session->frame_rate() / _session->timecode_frames_per_second);
1526 #ifdef Timecode_SAMPLE_TEST_1
1527 // Test 1: use_offset = false, use_subframes = false
1528 cout << "use_offset = false, use_subframes = false" << endl;
1529 for (int i = 0; i < 108003; i++) {
1530 _session->timecode_to_sample( timecode1, sample1, false /* use_offset */, false /* use_subframes */ );
1531 _session->sample_to_timecode( sample1, timecode2, false /* use_offset */, false /* use_subframes */ );
1533 if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) {
1534 cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1535 cout << "timecode1: " << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1536 cout << "sample: " << sample1 << endl;
1537 cout << "sample: " << sample1 << " -> ";
1538 cout << "timecode2: " << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1539 break;
1542 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1543 cout << "ERROR: timecode2 not equal timecode1" << endl;
1544 cout << "timecode1: " << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1545 cout << "sample: " << sample1 << endl;
1546 cout << "sample: " << sample1 << " -> ";
1547 cout << "timecode2: " << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1548 break;
1550 oldsample = sample1;
1551 _session->timecode_increment( timecode1 );
1554 cout << "sample_increment: " << sample_increment << endl;
1555 cout << "sample: " << sample1 << " -> ";
1556 cout << "timecode: " << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1557 #endif
1559 #ifdef Timecode_SAMPLE_TEST_2
1560 // Test 2: use_offset = true, use_subframes = false
1561 cout << "use_offset = true, use_subframes = false" << endl;
1563 timecode1.hours = 0;
1564 timecode1.minutes = 0;
1565 timecode1.seconds = 0;
1566 timecode1.frames = 0;
1567 timecode1.subframes = 0;
1568 sample1 = oldsample = 0;
1570 _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1571 cout << "Starting at sample: " << sample1 << " -> ";
1572 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1574 for (int i = 0; i < 108003; i++) {
1575 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1576 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1578 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1579 // cout << "sample: " << sample1 << endl;
1580 // cout << "sample: " << sample1 << " -> ";
1581 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1583 if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) {
1584 cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1585 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1586 cout << "sample: " << sample1 << endl;
1587 cout << "sample: " << sample1 << " -> ";
1588 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1589 break;
1592 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1593 cout << "ERROR: timecode2 not equal timecode1" << endl;
1594 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1595 cout << "sample: " << sample1 << endl;
1596 cout << "sample: " << sample1 << " -> ";
1597 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1598 break;
1600 oldsample = sample1;
1601 _session->timecode_increment( timecode1 );
1604 cout << "sample_increment: " << sample_increment << endl;
1605 cout << "sample: " << sample1 << " -> ";
1606 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1607 #endif
1609 #ifdef Timecode_SAMPLE_TEST_3
1610 // Test 3: use_offset = true, use_subframes = false, decrement
1611 cout << "use_offset = true, use_subframes = false, decrement" << endl;
1613 _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1614 cout << "Starting at sample: " << sample1 << " -> ";
1615 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1617 for (int i = 0; i < 108003; i++) {
1618 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1619 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1621 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1622 // cout << "sample: " << sample1 << endl;
1623 // cout << "sample: " << sample1 << " -> ";
1624 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1626 if ((i > 0) && ( ((oldsample - sample1) != sample_increment) && ((oldsample - sample1) != (sample_increment + 1)) && ((oldsample - sample1) != (sample_increment - 1)))) {
1627 cout << "ERROR: sample increment not right: " << (oldsample - sample1) << " != " << sample_increment << endl;
1628 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1629 cout << "sample: " << sample1 << endl;
1630 cout << "sample: " << sample1 << " -> ";
1631 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1632 break;
1635 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1636 cout << "ERROR: timecode2 not equal timecode1" << endl;
1637 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1638 cout << "sample: " << sample1 << endl;
1639 cout << "sample: " << sample1 << " -> ";
1640 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1641 break;
1643 oldsample = sample1;
1644 _session->timecode_decrement( timecode1 );
1647 cout << "sample_decrement: " << sample_increment << endl;
1648 cout << "sample: " << sample1 << " -> ";
1649 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1650 #endif
1653 #ifdef Timecode_SAMPLE_TEST_4
1654 // Test 4: use_offset = true, use_subframes = true
1655 cout << "use_offset = true, use_subframes = true" << endl;
1657 for (long sub = 5; sub < 80; sub += 5) {
1658 timecode1.hours = 0;
1659 timecode1.minutes = 0;
1660 timecode1.seconds = 0;
1661 timecode1.frames = 0;
1662 timecode1.subframes = 0;
1663 sample1 = oldsample = (sample_increment * sub) / 80;
1665 _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, true /* use_subframes */ );
1667 cout << "starting at sample: " << sample1 << " -> ";
1668 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1670 for (int i = 0; i < 108003; i++) {
1671 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, true /* use_subframes */ );
1672 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, true /* use_subframes */ );
1674 if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) {
1675 cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1676 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1677 cout << "sample: " << sample1 << endl;
1678 cout << "sample: " << sample1 << " -> ";
1679 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1680 //break;
1683 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames || timecode2.subframes != timecode1.subframes) {
1684 cout << "ERROR: timecode2 not equal timecode1" << endl;
1685 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1686 cout << "sample: " << sample1 << endl;
1687 cout << "sample: " << sample1 << " -> ";
1688 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1689 break;
1691 oldsample = sample1;
1692 _session->timecode_increment( timecode1 );
1695 cout << "sample_increment: " << sample_increment << endl;
1696 cout << "sample: " << sample1 << " -> ";
1697 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1699 for (int i = 0; i < 108003; i++) {
1700 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, true /* use_subframes */ );
1701 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, true /* use_subframes */ );
1703 if ((i > 0) && ( ((oldsample - sample1) != sample_increment) && ((oldsample - sample1) != (sample_increment + 1)) && ((oldsample - sample1) != (sample_increment - 1)))) {
1704 cout << "ERROR: sample increment not right: " << (oldsample - sample1) << " != " << sample_increment << endl;
1705 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1706 cout << "sample: " << sample1 << endl;
1707 cout << "sample: " << sample1 << " -> ";
1708 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1709 //break;
1712 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames || timecode2.subframes != timecode1.subframes) {
1713 cout << "ERROR: timecode2 not equal timecode1" << endl;
1714 cout << "timecode1: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1715 cout << "sample: " << sample1 << endl;
1716 cout << "sample: " << sample1 << " -> ";
1717 cout << "timecode2: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1718 break;
1720 oldsample = sample1;
1721 _session->timecode_decrement( timecode1 );
1724 cout << "sample_decrement: " << sample_increment << endl;
1725 cout << "sample: " << sample1 << " -> ";
1726 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1728 #endif
1731 #ifdef Timecode_SAMPLE_TEST_5
1732 // Test 5: use_offset = true, use_subframes = false, increment seconds
1733 cout << "use_offset = true, use_subframes = false, increment seconds" << endl;
1735 timecode1.hours = 0;
1736 timecode1.minutes = 0;
1737 timecode1.seconds = 0;
1738 timecode1.frames = 0;
1739 timecode1.subframes = 0;
1740 sample1 = oldsample = 0;
1741 sample_increment = _session->frame_rate();
1743 _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1744 cout << "Starting at sample: " << sample1 << " -> ";
1745 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1747 for (int i = 0; i < 3600; i++) {
1748 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1749 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1751 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1752 // cout << "sample: " << sample1 << endl;
1753 // cout << "sample: " << sample1 << " -> ";
1754 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1756 // if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1))))
1757 // {
1758 // cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1759 // break;
1760 // }
1762 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1763 cout << "ERROR: timecode2 not equal timecode1" << endl;
1764 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1765 cout << "sample: " << sample1 << endl;
1766 cout << "sample: " << sample1 << " -> ";
1767 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1768 break;
1770 oldsample = sample1;
1771 _session->timecode_increment_seconds( timecode1 );
1774 cout << "sample_increment: " << sample_increment << endl;
1775 cout << "sample: " << sample1 << " -> ";
1776 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1777 #endif
1780 #ifdef Timecode_SAMPLE_TEST_6
1781 // Test 6: use_offset = true, use_subframes = false, increment minutes
1782 cout << "use_offset = true, use_subframes = false, increment minutes" << endl;
1784 timecode1.hours = 0;
1785 timecode1.minutes = 0;
1786 timecode1.seconds = 0;
1787 timecode1.frames = 0;
1788 timecode1.subframes = 0;
1789 sample1 = oldsample = 0;
1790 sample_increment = _session->frame_rate() * 60;
1792 _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1793 cout << "Starting at sample: " << sample1 << " -> ";
1794 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1796 for (int i = 0; i < 60; i++) {
1797 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1798 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1800 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1801 // cout << "sample: " << sample1 << endl;
1802 // cout << "sample: " << sample1 << " -> ";
1803 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1805 // if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1))))
1806 // {
1807 // cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1808 // break;
1809 // }
1811 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1812 cout << "ERROR: timecode2 not equal timecode1" << endl;
1813 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1814 cout << "sample: " << sample1 << endl;
1815 cout << "sample: " << sample1 << " -> ";
1816 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1817 break;
1819 oldsample = sample1;
1820 _session->timecode_increment_minutes( timecode1 );
1823 cout << "sample_increment: " << sample_increment << endl;
1824 cout << "sample: " << sample1 << " -> ";
1825 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1826 #endif
1828 #ifdef Timecode_SAMPLE_TEST_7
1829 // Test 7: use_offset = true, use_subframes = false, increment hours
1830 cout << "use_offset = true, use_subframes = false, increment hours" << endl;
1832 timecode1.hours = 0;
1833 timecode1.minutes = 0;
1834 timecode1.seconds = 0;
1835 timecode1.frames = 0;
1836 timecode1.subframes = 0;
1837 sample1 = oldsample = 0;
1838 sample_increment = _session->frame_rate() * 60 * 60;
1840 _session->sample_to_timecode( sample1, timecode1, true /* use_offset */, false /* use_subframes */ );
1841 cout << "Starting at sample: " << sample1 << " -> ";
1842 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << endl;
1844 for (int i = 0; i < 10; i++) {
1845 _session->timecode_to_sample( timecode1, sample1, true /* use_offset */, false /* use_subframes */ );
1846 _session->sample_to_timecode( sample1, timecode2, true /* use_offset */, false /* use_subframes */ );
1848 // cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1849 // cout << "sample: " << sample1 << endl;
1850 // cout << "sample: " << sample1 << " -> ";
1851 // cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1853 // if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1))))
1854 // {
1855 // cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1856 // break;
1857 // }
1859 if (timecode2.hours != timecode1.hours || timecode2.minutes != timecode1.minutes || timecode2.seconds != timecode2.seconds || timecode2.frames != timecode1.frames) {
1860 cout << "ERROR: timecode2 not equal timecode1" << endl;
1861 cout << "timecode: " << (timecode1.negative ? "-" : "") << timecode1.hours << ":" << timecode1.minutes << ":" << timecode1.seconds << ":" << timecode1.frames << "::" << timecode1.subframes << " -> ";
1862 cout << "sample: " << sample1 << endl;
1863 cout << "sample: " << sample1 << " -> ";
1864 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1865 break;
1867 oldsample = sample1;
1868 _session->timecode_increment_hours( timecode1 );
1871 cout << "sample_increment: " << sample_increment << endl;
1872 cout << "sample: " << sample1 << " -> ";
1873 cout << "timecode: " << (timecode2.negative ? "-" : "") << timecode2.hours << ":" << timecode2.minutes << ":" << timecode2.seconds << ":" << timecode2.frames << "::" << timecode2.subframes << endl;
1874 #endif
1876 #endif
1878 return sample;
1881 nframes_t
1882 AudioClock::minsec_frame_from_display () const
1884 if (_session == 0) {
1885 return 0;
1888 int hrs = atoi (ms_hours_label.get_text());
1889 int mins = atoi (ms_minutes_label.get_text());
1890 float secs = atof (ms_seconds_label.get_text());
1892 nframes_t sr = _session->frame_rate();
1894 return (nframes_t) floor ((hrs * 60.0f * 60.0f * sr) + (mins * 60.0f * sr) + (secs * sr));
1897 nframes_t
1898 AudioClock::bbt_frame_from_display (nframes_t pos) const
1900 if (_session == 0) {
1901 error << "AudioClock::current_time() called with BBT mode but without session!" << endmsg;
1902 return 0;
1905 AnyTime any;
1906 any.type = AnyTime::BBT;
1908 any.bbt.bars = atoi (bars_label.get_text());
1909 any.bbt.beats = atoi (beats_label.get_text());
1910 any.bbt.ticks = atoi (ticks_label.get_text());
1912 if (is_duration) {
1913 any.bbt.bars++;
1914 any.bbt.beats++;
1917 nframes_t ret = _session->convert_to_frames_at (pos, any);
1919 return ret;
1923 nframes_t
1924 AudioClock::bbt_frame_duration_from_display (nframes_t pos) const
1926 if (_session == 0) {
1927 error << "AudioClock::current_time() called with BBT mode but without session!" << endmsg;
1928 return 0;
1931 BBT_Time bbt;
1934 bbt.bars = atoi (bars_label.get_text());
1935 bbt.beats = atoi (beats_label.get_text());
1936 bbt.ticks = atoi (ticks_label.get_text());
1938 return _session->tempo_map().bbt_duration_at(pos,bbt,1);
1941 nframes_t
1942 AudioClock::audio_frame_from_display () const
1944 return (nframes_t) atoi (audio_frames_label.get_text());
1947 void
1948 AudioClock::build_ops_menu ()
1950 using namespace Menu_Helpers;
1951 ops_menu = new Menu;
1952 MenuList& ops_items = ops_menu->items();
1953 ops_menu->set_name ("ArdourContextMenu");
1955 if (!Profile->get_sae()) {
1956 ops_items.push_back (MenuElem (_("Timecode"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), Timecode)));
1958 ops_items.push_back (MenuElem (_("Bars:Beats"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), BBT)));
1959 ops_items.push_back (MenuElem (_("Minutes:Seconds"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), MinSec)));
1960 ops_items.push_back (MenuElem (_("Samples"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), Frames)));
1961 ops_items.push_back (MenuElem (_("Off"), sigc::bind (sigc::mem_fun(*this, &AudioClock::set_mode), Off)));
1963 if (editable && !is_duration && !_follows_playhead) {
1964 ops_items.push_back (SeparatorElem());
1965 ops_items.push_back (MenuElem (_("Set From Playhead"), sigc::mem_fun(*this, &AudioClock::set_from_playhead)));
1966 ops_items.push_back (MenuElem (_("Locate to this time"), sigc::mem_fun(*this, &AudioClock::locate)));
1970 void
1971 AudioClock::set_from_playhead ()
1973 if (!_session) {
1974 return;
1977 set (_session->transport_frame());
1980 void
1981 AudioClock::locate ()
1983 if (!_session || is_duration) {
1984 return;
1987 _session->request_locate (current_time(), false);
1990 void
1991 AudioClock::set_mode (Mode m)
1993 /* slightly tricky: this is called from within the ARDOUR_UI
1994 constructor by some of its clock members. at that time
1995 the instance pointer is unset, so we have to be careful.
1996 the main idea is to drop keyboard focus in case we had
1997 started editing the clock and then we switch clock mode.
2000 clock_base.grab_focus ();
2002 if (_mode == m) {
2003 return;
2006 clock_base.remove ();
2008 _mode = m;
2010 switch (_mode) {
2011 case Timecode:
2012 clock_base.add (timecode_packer_hbox);
2013 break;
2015 case BBT:
2016 clock_base.add (bbt_packer_hbox);
2017 break;
2019 case MinSec:
2020 clock_base.add (minsec_packer_hbox);
2021 break;
2023 case Frames:
2024 clock_base.add (frames_packer_hbox);
2025 break;
2027 case Off:
2028 clock_base.add (off_hbox);
2029 break;
2032 set_size_requests ();
2034 set (last_when, true);
2035 clock_base.show_all ();
2036 key_entry_state = 0;
2038 if (!is_transient) {
2039 ModeChanged (); /* EMIT SIGNAL */
2040 mode_changed (); /* EMIT SIGNAL */
2044 void
2045 AudioClock::set_size_requests ()
2047 /* note that in some fonts, "88" is narrower than "00" */
2049 switch (_mode) {
2050 case Timecode:
2051 Gtkmm2ext::set_size_request_to_display_given_text (hours_label, "-88", 5, 5);
2052 Gtkmm2ext::set_size_request_to_display_given_text (minutes_label, "88", 5, 5);
2053 Gtkmm2ext::set_size_request_to_display_given_text (seconds_label, "88", 5, 5);
2054 Gtkmm2ext::set_size_request_to_display_given_text (frames_label, "88", 5, 5);
2055 break;
2057 case BBT:
2058 Gtkmm2ext::set_size_request_to_display_given_text (bars_label, "-888", 5, 5);
2059 Gtkmm2ext::set_size_request_to_display_given_text (beats_label, "88", 5, 5);
2060 Gtkmm2ext::set_size_request_to_display_given_text (ticks_label, "8888", 5, 5);
2061 break;
2063 case MinSec:
2064 Gtkmm2ext::set_size_request_to_display_given_text (ms_hours_label, "88", 5, 5);
2065 Gtkmm2ext::set_size_request_to_display_given_text (ms_minutes_label, "88", 5, 5);
2066 Gtkmm2ext::set_size_request_to_display_given_text (ms_seconds_label, "88.888", 5, 5);
2067 break;
2069 case Frames:
2070 Gtkmm2ext::set_size_request_to_display_given_text (audio_frames_label, "8888888888", 5, 5);
2071 break;
2073 case Off:
2074 Gtkmm2ext::set_size_request_to_display_given_text (off_hbox, "00000", 5, 5);
2075 break;
2080 void
2081 AudioClock::set_bbt_reference (nframes64_t pos)
2083 bbt_reference_time = pos;
2086 void
2087 AudioClock::on_style_changed (const Glib::RefPtr<Style>& old_style)
2089 HBox::on_style_changed (old_style);
2091 /* propagate style changes to all component widgets that should inherit the main one */
2093 Glib::RefPtr<RcStyle> rcstyle = get_modifier_style();
2095 clock_base.modify_style (rcstyle);
2096 audio_frames_label.modify_style (rcstyle);
2097 hours_label.modify_style (rcstyle);
2098 minutes_label.modify_style (rcstyle);
2099 seconds_label.modify_style (rcstyle);
2100 frames_label.modify_style (rcstyle);
2101 bars_label.modify_style (rcstyle);
2102 beats_label.modify_style (rcstyle);
2103 ticks_label.modify_style (rcstyle);
2104 ms_hours_label.modify_style (rcstyle);
2105 ms_minutes_label.modify_style (rcstyle);
2106 ms_seconds_label.modify_style (rcstyle);
2107 hours_ebox.modify_style (rcstyle);
2108 minutes_ebox.modify_style (rcstyle);
2109 seconds_ebox.modify_style (rcstyle);
2110 frames_ebox.modify_style (rcstyle);
2111 audio_frames_ebox.modify_style (rcstyle);
2112 bars_ebox.modify_style (rcstyle);
2113 beats_ebox.modify_style (rcstyle);
2114 ticks_ebox.modify_style (rcstyle);
2115 ms_hours_ebox.modify_style (rcstyle);
2116 ms_minutes_ebox.modify_style (rcstyle);
2117 ms_seconds_ebox.modify_style (rcstyle);
2119 colon1.modify_style (rcstyle);
2120 colon2.modify_style (rcstyle);
2121 colon3.modify_style (rcstyle);
2122 colon4.modify_style (rcstyle);
2123 colon5.modify_style (rcstyle);
2124 b1.modify_style (rcstyle);
2125 b2.modify_style (rcstyle);
2127 set_size_requests ();