Merged with trunk R1283.
[ardour.git] / gtk2_ardour / audio_clock.cc
1 /*
2     Copyright (C) 1999 Paul Davis 
3
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.
8
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.
13
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.
17
18     $Id$
19 */
20
21 #include <cstdio> // for sprintf
22 #include <cmath>
23
24 #include <pbd/convert.h>
25 #include <pbd/enumwriter.h>
26
27 #include <gtkmm2ext/utils.h>
28
29 #include <ardour/ardour.h>
30 #include <ardour/session.h>
31 #include <ardour/tempo.h>
32 #include <sigc++/bind.h>
33
34 #include "ardour_ui.h"
35 #include "audio_clock.h"
36 #include "utils.h"
37 #include "keyboard.h"
38 #include "i18n.h"
39
40 using namespace ARDOUR;
41 using namespace PBD;
42 using namespace sigc;
43 using namespace Gtk;
44 using namespace std;
45
46 using PBD::atoi;
47 using PBD::atof;
48
49 sigc::signal<void> AudioClock::ModeChanged;
50 vector<AudioClock*> AudioClock::clocks;
51
52 const uint32_t AudioClock::field_length[(int) AudioClock::AudioFrames+1] = {
53         2,   /* SMPTE_Hours */
54         2,   /* SMPTE_Minutes */
55         2,   /* SMPTE_Seconds */
56         2,   /* SMPTE_Frames */
57         2,   /* MS_Hours */
58         2,   /* MS_Minutes */
59         5,   /* MS_Seconds */
60         3,   /* Bars */
61         2,   /* Beats */
62         4,   /* Tick */
63         10   /* Audio Frame */
64 };
65
66 AudioClock::AudioClock (std::string clock_name, bool transient, std::string widget_name, bool allow_edit, bool duration, bool with_info) 
67         : _name (clock_name),
68           is_transient (transient),
69           is_duration (duration),
70           editable (allow_edit),
71           colon1 (":"),
72           colon2 (":"),
73           colon3 (":"),
74           colon4 (":"),
75           colon5 (":"),
76           b1 ("|"),
77           b2 ("|")
78 {
79         session = 0;
80         last_when = 0;
81         key_entry_state = 0;
82         ops_menu = 0;
83         dragging = false;
84         
85         if (with_info) {
86                 frames_upper_info_label = manage (new Label);
87                 frames_lower_info_label = manage (new Label);
88                 smpte_upper_info_label = manage (new Label);
89                 smpte_lower_info_label = manage (new Label);
90                 bbt_upper_info_label = manage (new Label);
91                 bbt_lower_info_label = manage (new Label);
92                 
93                 frames_upper_info_label->set_name ("AudioClockFramesUpperInfo");
94                 frames_lower_info_label->set_name ("AudioClockFramesLowerInfo");
95                 smpte_upper_info_label->set_name ("AudioClockSMPTEUpperInfo");
96                 smpte_lower_info_label->set_name ("AudioClockSMPTELowerInfo");
97                 bbt_upper_info_label->set_name ("AudioClockBBTUpperInfo");
98                 bbt_lower_info_label->set_name ("AudioClockBBTLowerInfo");
99
100                 Gtkmm2ext::set_size_request_to_display_given_text(*smpte_upper_info_label, "23.98",0,0);
101                 Gtkmm2ext::set_size_request_to_display_given_text(*smpte_lower_info_label, "NDF",0,0);
102
103                 frames_info_box.pack_start (*frames_upper_info_label, true, true);
104                 frames_info_box.pack_start (*frames_lower_info_label, true, true);
105                 smpte_info_box.pack_start (*smpte_upper_info_label, true, true);
106                 smpte_info_box.pack_start (*smpte_lower_info_label, true, true);
107                 bbt_info_box.pack_start (*bbt_upper_info_label, true, true);
108                 bbt_info_box.pack_start (*bbt_lower_info_label, true, true);
109                 
110         } else {
111                 frames_upper_info_label = 0;
112                 frames_lower_info_label = 0;
113                 smpte_upper_info_label = 0;
114                 smpte_lower_info_label = 0;
115                 bbt_upper_info_label = 0;
116                 bbt_lower_info_label = 0;
117         }       
118         
119         audio_frames_ebox.add (audio_frames_label);
120         
121         frames_packer.set_homogeneous (false);
122         frames_packer.set_border_width (2);
123         frames_packer.pack_start (audio_frames_ebox, false, false);
124         
125         if (with_info) {
126                 frames_packer.pack_start (frames_info_box, false, false, 5);
127         }
128         
129         frames_packer_hbox.pack_start (frames_packer, true, false);
130
131         hours_ebox.add (hours_label);
132         minutes_ebox.add (minutes_label);
133         seconds_ebox.add (seconds_label);
134         frames_ebox.add (frames_label);
135         bars_ebox.add (bars_label);
136         beats_ebox.add (beats_label);
137         ticks_ebox.add (ticks_label);
138         ms_hours_ebox.add (ms_hours_label);
139         ms_minutes_ebox.add (ms_minutes_label);
140         ms_seconds_ebox.add (ms_seconds_label);
141
142         smpte_packer.set_homogeneous (false);
143         smpte_packer.set_border_width (2);
144         smpte_packer.pack_start (hours_ebox, false, false);
145         smpte_packer.pack_start (colon1, false, false);
146         smpte_packer.pack_start (minutes_ebox, false, false);
147         smpte_packer.pack_start (colon2, false, false);
148         smpte_packer.pack_start (seconds_ebox, false, false);
149         smpte_packer.pack_start (colon3, false, false);
150         smpte_packer.pack_start (frames_ebox, false, false);
151
152         if (with_info) {
153                 smpte_packer.pack_start (smpte_info_box, false, false, 5);
154         }
155
156         smpte_packer_hbox.pack_start (smpte_packer, true, false);
157
158         bbt_packer.set_homogeneous (false);
159         bbt_packer.set_border_width (2);
160         bbt_packer.pack_start (bars_ebox, false, false);
161         bbt_packer.pack_start (b1, false, false);
162         bbt_packer.pack_start (beats_ebox, false, false);
163         bbt_packer.pack_start (b2, false, false);
164         bbt_packer.pack_start (ticks_ebox, false, false);
165
166         if (with_info) {
167                 bbt_packer.pack_start (bbt_info_box, false, false, 5);
168         }
169
170         bbt_packer_hbox.pack_start (bbt_packer, true, false);
171
172         minsec_packer.set_homogeneous (false);
173         minsec_packer.set_border_width (2);
174         minsec_packer.pack_start (ms_hours_ebox, false, false);
175         minsec_packer.pack_start (colon4, false, false);
176         minsec_packer.pack_start (ms_minutes_ebox, false, false);
177         minsec_packer.pack_start (colon5, false, false);
178         minsec_packer.pack_start (ms_seconds_ebox, false, false);
179
180         minsec_packer_hbox.pack_start (minsec_packer, true, false);
181
182         clock_frame.set_shadow_type (Gtk::SHADOW_IN);
183         clock_frame.set_name ("BaseFrame");
184
185         clock_frame.add (clock_base);
186
187         set_widget_name (widget_name);
188
189         _mode = BBT; /* lie to force mode switch */
190         set_mode (SMPTE);
191
192         pack_start (clock_frame, true, true);
193
194         /* the clock base handles button releases for menu popup regardless of
195            editable status. if the clock is editable, the clock base is where
196            we pass focus to after leaving the last editable "field", which
197            will then shutdown editing till the user starts it up again.
198
199            it does this because the focus out event on the field disables
200            keyboard event handling, and we don't connect anything up to
201            notice focus in on the clock base. hence, keyboard event handling
202            stays disabled.
203         */
204
205         clock_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::SCROLL_MASK);
206         clock_base.signal_button_release_event().connect (bind (mem_fun (*this, &AudioClock::field_button_release_event), SMPTE_Hours));
207
208         Session::SMPTEOffsetChanged.connect (mem_fun (*this, &AudioClock::smpte_offset_changed));
209
210         if (editable) {
211                 setup_events ();
212         }
213
214         set (last_when, true);
215
216         if (!is_transient) {
217                 clocks.push_back (this);
218         }
219 }
220
221 void
222 AudioClock::set_widget_name (string name)
223 {
224         Widget::set_name (name);
225
226         clock_base.set_name (name);
227
228         audio_frames_label.set_name (name);
229         hours_label.set_name (name);
230         minutes_label.set_name (name);
231         seconds_label.set_name (name);
232         frames_label.set_name (name);
233         bars_label.set_name (name);
234         beats_label.set_name (name);
235         ticks_label.set_name (name);
236         ms_hours_label.set_name (name);
237         ms_minutes_label.set_name (name);
238         ms_seconds_label.set_name (name);
239         hours_ebox.set_name (name);
240         minutes_ebox.set_name (name);
241         seconds_ebox.set_name (name);
242         frames_ebox.set_name (name);
243         audio_frames_ebox.set_name (name);
244         bars_ebox.set_name (name);
245         beats_ebox.set_name (name);
246         ticks_ebox.set_name (name);
247         ms_hours_ebox.set_name (name);
248         ms_minutes_ebox.set_name (name);
249         ms_seconds_ebox.set_name (name);
250         
251         colon1.set_name (name);
252         colon2.set_name (name);
253         colon3.set_name (name);
254         colon4.set_name (name);
255         colon5.set_name (name);
256         b1.set_name (name);
257         b2.set_name (name);
258
259         queue_draw ();
260 }
261
262 void
263 AudioClock::setup_events ()
264 {
265         clock_base.set_flags (Gtk::CAN_FOCUS);
266
267         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);
268         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);
269         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);
270         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);
271         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);
272         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);
273         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);
274         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);
275         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);
276         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);
277         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);
278
279         hours_ebox.set_flags (Gtk::CAN_FOCUS);
280         minutes_ebox.set_flags (Gtk::CAN_FOCUS);
281         seconds_ebox.set_flags (Gtk::CAN_FOCUS);
282         frames_ebox.set_flags (Gtk::CAN_FOCUS);
283         audio_frames_ebox.set_flags (Gtk::CAN_FOCUS);
284         bars_ebox.set_flags (Gtk::CAN_FOCUS);
285         beats_ebox.set_flags (Gtk::CAN_FOCUS);
286         ticks_ebox.set_flags (Gtk::CAN_FOCUS);
287         ms_hours_ebox.set_flags (Gtk::CAN_FOCUS);
288         ms_minutes_ebox.set_flags (Gtk::CAN_FOCUS);
289         ms_seconds_ebox.set_flags (Gtk::CAN_FOCUS);
290
291         hours_ebox.signal_motion_notify_event().connect (bind (mem_fun(*this, &AudioClock::field_motion_notify_event), SMPTE_Hours));
292         minutes_ebox.signal_motion_notify_event().connect (bind (mem_fun(*this, &AudioClock::field_motion_notify_event), SMPTE_Minutes));
293         seconds_ebox.signal_motion_notify_event().connect (bind (mem_fun(*this, &AudioClock::field_motion_notify_event), SMPTE_Seconds));
294         frames_ebox.signal_motion_notify_event().connect (bind (mem_fun(*this, &AudioClock::field_motion_notify_event), SMPTE_Frames));
295         audio_frames_ebox.signal_motion_notify_event().connect (bind (mem_fun(*this, &AudioClock::field_motion_notify_event), AudioFrames));
296         bars_ebox.signal_motion_notify_event().connect (bind (mem_fun(*this, &AudioClock::field_motion_notify_event), Bars));
297         beats_ebox.signal_motion_notify_event().connect (bind (mem_fun(*this, &AudioClock::field_motion_notify_event), Beats));
298         ticks_ebox.signal_motion_notify_event().connect (bind (mem_fun(*this, &AudioClock::field_motion_notify_event), Ticks));
299         ms_hours_ebox.signal_motion_notify_event().connect (bind (mem_fun(*this, &AudioClock::field_motion_notify_event), MS_Hours));
300         ms_minutes_ebox.signal_motion_notify_event().connect (bind (mem_fun(*this, &AudioClock::field_motion_notify_event), MS_Minutes));
301         ms_seconds_ebox.signal_motion_notify_event().connect (bind (mem_fun(*this, &AudioClock::field_motion_notify_event), MS_Seconds));
302
303         hours_ebox.signal_button_press_event().connect (bind (mem_fun(*this, &AudioClock::field_button_press_event), SMPTE_Hours));
304         minutes_ebox.signal_button_press_event().connect (bind (mem_fun(*this, &AudioClock::field_button_press_event), SMPTE_Minutes));
305         seconds_ebox.signal_button_press_event().connect (bind (mem_fun(*this, &AudioClock::field_button_press_event), SMPTE_Seconds));
306         frames_ebox.signal_button_press_event().connect (bind (mem_fun(*this, &AudioClock::field_button_press_event), SMPTE_Frames));
307         audio_frames_ebox.signal_button_press_event().connect (bind (mem_fun(*this, &AudioClock::field_button_press_event), AudioFrames));
308         bars_ebox.signal_button_press_event().connect (bind (mem_fun(*this, &AudioClock::field_button_press_event), Bars));
309         beats_ebox.signal_button_press_event().connect (bind (mem_fun(*this, &AudioClock::field_button_press_event), Beats));
310         ticks_ebox.signal_button_press_event().connect (bind (mem_fun(*this, &AudioClock::field_button_press_event), Ticks));
311         ms_hours_ebox.signal_button_press_event().connect (bind (mem_fun(*this, &AudioClock::field_button_press_event), MS_Hours));
312         ms_minutes_ebox.signal_button_press_event().connect (bind (mem_fun(*this, &AudioClock::field_button_press_event), MS_Minutes));
313         ms_seconds_ebox.signal_button_press_event().connect (bind (mem_fun(*this, &AudioClock::field_button_press_event), MS_Seconds));
314
315         hours_ebox.signal_button_release_event().connect (bind (mem_fun(*this, &AudioClock::field_button_release_event), SMPTE_Hours));
316         minutes_ebox.signal_button_release_event().connect (bind (mem_fun(*this, &AudioClock::field_button_release_event), SMPTE_Minutes));
317         seconds_ebox.signal_button_release_event().connect (bind (mem_fun(*this, &AudioClock::field_button_release_event), SMPTE_Seconds));
318         frames_ebox.signal_button_release_event().connect (bind (mem_fun(*this, &AudioClock::field_button_release_event), SMPTE_Frames));
319         audio_frames_ebox.signal_button_release_event().connect (bind (mem_fun(*this, &AudioClock::field_button_release_event), AudioFrames));
320         bars_ebox.signal_button_release_event().connect (bind (mem_fun(*this, &AudioClock::field_button_release_event), Bars));
321         beats_ebox.signal_button_release_event().connect (bind (mem_fun(*this, &AudioClock::field_button_release_event), Beats));
322         ticks_ebox.signal_button_release_event().connect (bind (mem_fun(*this, &AudioClock::field_button_release_event), Ticks));
323         ms_hours_ebox.signal_button_release_event().connect (bind (mem_fun(*this, &AudioClock::field_button_release_event), MS_Hours));
324         ms_minutes_ebox.signal_button_release_event().connect (bind (mem_fun(*this, &AudioClock::field_button_release_event), MS_Minutes));
325         ms_seconds_ebox.signal_button_release_event().connect (bind (mem_fun(*this, &AudioClock::field_button_release_event), MS_Seconds));
326
327         hours_ebox.signal_scroll_event().connect (bind (mem_fun(*this, &AudioClock::field_button_scroll_event), SMPTE_Hours));
328         minutes_ebox.signal_scroll_event().connect (bind (mem_fun(*this, &AudioClock::field_button_scroll_event), SMPTE_Minutes));
329         seconds_ebox.signal_scroll_event().connect (bind (mem_fun(*this, &AudioClock::field_button_scroll_event), SMPTE_Seconds));
330         frames_ebox.signal_scroll_event().connect (bind (mem_fun(*this, &AudioClock::field_button_scroll_event), SMPTE_Frames));
331         audio_frames_ebox.signal_scroll_event().connect (bind (mem_fun(*this, &AudioClock::field_button_scroll_event), AudioFrames));
332         bars_ebox.signal_scroll_event().connect (bind (mem_fun(*this, &AudioClock::field_button_scroll_event), Bars));
333         beats_ebox.signal_scroll_event().connect (bind (mem_fun(*this, &AudioClock::field_button_scroll_event), Beats));
334         ticks_ebox.signal_scroll_event().connect (bind (mem_fun(*this, &AudioClock::field_button_scroll_event), Ticks));
335         ms_hours_ebox.signal_scroll_event().connect (bind (mem_fun(*this, &AudioClock::field_button_scroll_event), MS_Hours));
336         ms_minutes_ebox.signal_scroll_event().connect (bind (mem_fun(*this, &AudioClock::field_button_scroll_event), MS_Minutes));
337         ms_seconds_ebox.signal_scroll_event().connect (bind (mem_fun(*this, &AudioClock::field_button_scroll_event), MS_Seconds));
338
339         hours_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), SMPTE_Hours));
340         minutes_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), SMPTE_Minutes));
341         seconds_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), SMPTE_Seconds));
342         frames_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), SMPTE_Frames));
343         audio_frames_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), AudioFrames));
344         bars_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), Bars));
345         beats_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), Beats));
346         ticks_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), Ticks));
347         ms_hours_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), MS_Hours));
348         ms_minutes_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), MS_Minutes));
349         ms_seconds_ebox.signal_key_release_event().connect (bind (mem_fun(*this, &AudioClock::field_key_release_event), MS_Seconds));
350
351         hours_ebox.signal_focus_in_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_in_event), SMPTE_Hours));
352         minutes_ebox.signal_focus_in_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_in_event), SMPTE_Minutes));
353         seconds_ebox.signal_focus_in_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_in_event), SMPTE_Seconds));
354         frames_ebox.signal_focus_in_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_in_event), SMPTE_Frames));
355         audio_frames_ebox.signal_focus_in_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_in_event), AudioFrames));
356         bars_ebox.signal_focus_in_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_in_event), Bars));
357         beats_ebox.signal_focus_in_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_in_event), Beats));
358         ticks_ebox.signal_focus_in_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_in_event), Ticks));
359         ms_hours_ebox.signal_focus_in_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_in_event), MS_Hours));
360         ms_minutes_ebox.signal_focus_in_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_in_event), MS_Minutes));
361         ms_seconds_ebox.signal_focus_in_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_in_event), MS_Seconds));
362
363         hours_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), SMPTE_Hours));
364         minutes_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), SMPTE_Minutes));
365         seconds_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), SMPTE_Seconds));
366         frames_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), SMPTE_Frames));
367         audio_frames_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), AudioFrames));
368         bars_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), Bars));
369         beats_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), Beats));
370         ticks_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), Ticks));
371         ms_hours_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), MS_Hours));
372         ms_minutes_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), MS_Minutes));
373         ms_seconds_ebox.signal_focus_out_event().connect (bind (mem_fun(*this, &AudioClock::field_focus_out_event), MS_Seconds));
374 }
375
376 void
377 AudioClock::on_realize ()
378 {
379         HBox::on_realize ();
380
381         /* styles are not available until the widgets are bound to a window */
382
383         set_size_requests ();
384 }
385
386 void
387 AudioClock::set (nframes_t when, bool force)
388 {
389
390         if ((!force && !is_visible()) || session == 0) {
391                 return;
392         }
393         
394         if (when == last_when && !force) {
395                 return;
396         }
397
398         switch (_mode) {
399         case SMPTE:
400                 set_smpte (when, force);
401                 break;
402
403         case BBT:
404                 set_bbt (when, force);
405                 break;
406
407         case MinSec:
408                 set_minsec (when, force);
409                 break;
410
411         case Frames:
412                 set_frames (when, force);
413                 break;
414
415         case Off:
416                 break;
417         }
418
419         last_when = when;
420 }
421
422 void
423 AudioClock::smpte_offset_changed ()
424 {
425         nframes_t current;
426
427         switch (_mode) {
428         case SMPTE:
429                 if (is_duration) {
430                         current = current_duration();
431                 } else {
432                         current = current_time ();
433                 }
434                 set (current, true);
435                 break;
436         default:
437                 break;
438         }
439 }
440
441 void
442 AudioClock::set_frames (nframes_t when, bool force)
443 {
444         char buf[32];
445         snprintf (buf, sizeof (buf), "%u", when);
446         audio_frames_label.set_text (buf);
447         
448         if (frames_upper_info_label) {
449                 nframes_t rate = session->frame_rate();
450                 
451                 if (fmod (rate, 1000.0) == 0.000) {
452                         sprintf (buf, "%uK", rate/1000);
453                 } else {
454                         sprintf (buf, "%.3fK", rate/1000.0f);
455                 }
456                 
457                 frames_upper_info_label->set_text (buf);
458                 
459                 float vid_pullup = Config->get_video_pullup();
460                 
461                 if (vid_pullup == 0.0) {
462                         frames_lower_info_label->set_text(_("none"));
463                 } else {
464                         sprintf (buf, "%-6.4f", vid_pullup);
465                         frames_lower_info_label->set_text (buf);
466                 }
467         }
468 }       
469
470 void
471 AudioClock::set_minsec (nframes_t when, bool force)
472 {
473         char buf[32];
474         nframes_t left;
475         int hrs;
476         int mins;
477         float secs;
478         
479         left = when;
480         hrs = (int) floor (left / (session->frame_rate() * 60.0f * 60.0f));
481         left -= (nframes_t) floor (hrs * session->frame_rate() * 60.0f * 60.0f);
482         mins = (int) floor (left / (session->frame_rate() * 60.0f));
483         left -= (nframes_t) floor (mins * session->frame_rate() * 60.0f);
484         secs = left / (float) session->frame_rate();
485
486         if (force || hrs != ms_last_hrs) {
487                 sprintf (buf, "%02d", hrs);
488                 ms_hours_label.set_text (buf);
489                 ms_last_hrs = hrs;
490         }
491
492         if (force || mins != ms_last_mins) {
493                 sprintf (buf, "%02d", mins);
494                 ms_minutes_label.set_text (buf);
495                 ms_last_mins = mins;
496         }
497
498         if (force || secs != ms_last_secs) {
499                 sprintf (buf, "%06.3f", secs);
500                 ms_seconds_label.set_text (buf);
501                 ms_last_secs = secs;
502         }
503 }
504
505 void
506 AudioClock::set_smpte (nframes_t when, bool force)
507 {
508         char buf[32];
509         SMPTE::Time smpte;
510         
511         if (is_duration) {
512                 session->smpte_duration (when, smpte);
513         } else {
514                 session->smpte_time (when, smpte);
515         }
516
517         if (force || smpte.hours != last_hrs || smpte.negative != last_negative) {
518                 if (smpte.negative) {
519                         sprintf (buf, "-%02" PRIu32, smpte.hours);
520                 } else {
521                         sprintf (buf, " %02" PRIu32, smpte.hours);
522                 }
523                 hours_label.set_text (buf);
524                 last_hrs = smpte.hours;
525                 last_negative = smpte.negative;
526         }
527
528         if (force || smpte.minutes != last_mins) {
529                 sprintf (buf, "%02" PRIu32, smpte.minutes);
530                 minutes_label.set_text (buf);
531                 last_mins = smpte.minutes;
532         }
533
534         if (force || smpte.seconds != last_secs) {
535                 sprintf (buf, "%02" PRIu32, smpte.seconds);
536                 seconds_label.set_text (buf);
537                 last_secs = smpte.seconds;
538         }
539
540         if (force || smpte.frames != last_frames) {
541                 sprintf (buf, "%02" PRIu32, smpte.frames);
542                 frames_label.set_text (buf);
543                 last_frames = smpte.frames;
544         }
545         
546         if (smpte_upper_info_label) {
547                 double smpte_frames = session->smpte_frames_per_second();
548                 
549                 if ( fmod(smpte_frames, 1.0) == 0.0) {
550                         sprintf (buf, "%u", int (smpte_frames)); 
551                 } else {
552                         sprintf (buf, "%.2f", smpte_frames);
553                 }
554                 
555                 smpte_upper_info_label->set_text (buf);
556                 
557                 if (session->smpte_drop_frames()) {
558                         sprintf (buf, "DF");
559                 } else {
560                         sprintf (buf, "NDF");
561                 }
562                 
563                 smpte_lower_info_label->set_text (buf);
564         }
565 }
566
567 void
568 AudioClock::set_bbt (nframes_t when, bool force)
569 {
570         char buf[16];
571         BBT_Time bbt;
572
573         session->tempo_map().bbt_time (when, bbt);
574         sprintf (buf, "%03" PRIu32, bbt.bars);
575         bars_label.set_text (buf);
576         sprintf (buf, "%02" PRIu32, bbt.beats);
577         beats_label.set_text (buf);
578         sprintf (buf, "%04" PRIu32, bbt.ticks);
579         ticks_label.set_text (buf);
580         
581         if (bbt_upper_info_label) {
582                 TempoMap::Metric m (session->tempo_map().metric_at (when));
583                 sprintf (buf, "%-5.2f", m.tempo().beats_per_minute());
584                 bbt_lower_info_label->set_text (buf);
585                 sprintf (buf, "%g|%g", m.meter().beats_per_bar(), m.meter().note_divisor());
586                 bbt_upper_info_label->set_text (buf);
587         }
588 }
589
590 void
591 AudioClock::set_session (Session *s)
592 {
593         session = s;
594
595         if (s) {
596
597                 XMLProperty* prop;
598                 XMLNode* node = session->extra_xml (X_("ClockModes"));
599                 AudioClock::Mode amode;
600                 
601                 if (node) {
602                         if ((prop = node->property (_name.c_str())) != 0) {
603                                 amode = AudioClock::Mode (string_2_enum (prop->value(), amode));
604                                 set_mode (amode);
605                         }
606                 }
607
608                 set (last_when, true);
609         }
610 }
611
612 bool
613 AudioClock::field_key_release_event (GdkEventKey *ev, Field field)
614 {
615         Label *label = 0;
616         string new_text;
617         char new_char = 0;
618         bool move_on = false;
619
620         switch (field) {
621         case SMPTE_Hours:
622                 label = &hours_label;
623                 break;
624         case SMPTE_Minutes:
625                 label = &minutes_label;
626                 break;
627         case SMPTE_Seconds:
628                 label = &seconds_label;
629                 break;
630         case SMPTE_Frames:
631                 label = &frames_label;
632                 break;
633
634         case AudioFrames:
635                 label = &audio_frames_label;
636                 break;
637
638         case MS_Hours:
639                 label = &ms_hours_label;
640                 break;
641         case MS_Minutes:
642                 label = &ms_minutes_label;
643                 break;
644         case MS_Seconds:
645                 label = &ms_seconds_label;
646                 break;
647
648         case Bars:
649                 label = &bars_label;
650                 break;
651         case Beats:
652                 label = &beats_label;
653                 break;
654         case Ticks:
655                 label = &ticks_label;
656                 break;
657         default:
658                 return FALSE;
659         }
660
661         switch (ev->keyval) {
662         case GDK_0:
663         case GDK_KP_0:
664                 new_char = '0';
665                 break;
666         case GDK_1:
667         case GDK_KP_1:
668                 new_char = '1';
669                 break;
670         case GDK_2:
671         case GDK_KP_2:
672                 new_char = '2';
673                 break;
674         case GDK_3:
675         case GDK_KP_3:
676                 new_char = '3';
677                 break;
678         case GDK_4:
679         case GDK_KP_4:
680                 new_char = '4';
681                 break;
682         case GDK_5:
683         case GDK_KP_5:
684                 new_char = '5';
685                 break;
686         case GDK_6:
687         case GDK_KP_6:
688                 new_char = '6';
689                 break;
690         case GDK_7:
691         case GDK_KP_7:
692                 new_char = '7';
693                 break;
694         case GDK_8:
695         case GDK_KP_8:
696                 new_char = '8';
697                 break;
698         case GDK_9:
699         case GDK_KP_9:
700                 new_char = '9';
701                 break;
702
703         case GDK_period:
704         case GDK_KP_Decimal:
705                 if (_mode == MinSec && field == MS_Seconds) {
706                         new_char = '.';
707                 } else {
708                         return FALSE;
709                 }
710                 break;
711
712         case GDK_Return:
713         case GDK_KP_Enter:
714         case GDK_Tab:
715                 move_on = true;
716                 break;
717
718         case GDK_Escape:
719                 clock_base.grab_focus ();
720                 return TRUE;
721
722         default:
723                 return FALSE;
724         }
725
726         if (!move_on) {
727
728                 if (key_entry_state == 0) {
729
730                         /* initialize with a fresh new string */
731
732                         if (field != AudioFrames) {
733                                 for (uint32_t xn = 0; xn < field_length[field] - 1; ++xn) {
734                                         new_text += '0';
735                                 }
736                         } else {
737                                 new_text = "";
738                         }
739
740                 } else {
741
742                         string existing = label->get_text();
743                         if (existing.length() >= field_length[field]) {
744                                 new_text = existing.substr (1, field_length[field] - 1);
745                         } else {
746                                 new_text = existing.substr (0, field_length[field] - 1);
747                         }
748                 }
749
750                 new_text += new_char;
751                 label->set_text (new_text);
752                 key_entry_state++;
753         }
754
755         if (key_entry_state == field_length[field]) {
756                 move_on = true;
757         }
758         
759         if (move_on) {
760
761                 if (key_entry_state) {
762       
763                         switch (field) {
764                         case SMPTE_Hours:
765                         case SMPTE_Minutes:
766                         case SMPTE_Seconds:
767                         case SMPTE_Frames:
768                                 // Check SMPTE fields for sanity (may also adjust fields)
769                                 smpte_sanitize_display();
770                                 break;
771                         default:
772                                 break;
773                         }
774                         
775                         ValueChanged(); /* EMIT_SIGNAL */
776                 }
777                 
778                 /* move on to the next field.
779                  */
780                 
781                 switch (field) {
782                         
783                         /* SMPTE */
784                         
785                 case SMPTE_Hours:
786                         minutes_ebox.grab_focus ();
787                         break;
788                 case SMPTE_Minutes:
789                         seconds_ebox.grab_focus ();
790                         break;
791                 case SMPTE_Seconds:
792                         frames_ebox.grab_focus ();
793                         break;
794                 case SMPTE_Frames:
795                         clock_base.grab_focus ();
796                         break;
797
798                 /* audio frames */
799                 case AudioFrames:
800                         clock_base.grab_focus ();
801                         break;
802
803                 /* Min:Sec */
804
805                 case MS_Hours:
806                         ms_minutes_ebox.grab_focus ();
807                         break;
808                 case MS_Minutes:
809                         ms_seconds_ebox.grab_focus ();
810                         break;
811                 case MS_Seconds:
812                         clock_base.grab_focus ();
813                         break;
814
815                 /* BBT */
816
817                 case Bars:
818                         beats_ebox.grab_focus ();
819                         break;
820                 case Beats:
821                         ticks_ebox.grab_focus ();
822                         break;
823                 case Ticks:
824                         clock_base.grab_focus ();
825                         break;
826
827                 default:
828                         break;
829                 }
830
831         }
832
833         return TRUE;
834 }
835
836 bool
837 AudioClock::field_focus_in_event (GdkEventFocus *ev, Field field)
838 {
839         key_entry_state = 0;
840
841         switch (field) {
842         case SMPTE_Hours:
843                 hours_ebox.set_flags (Gtk::HAS_FOCUS);
844                 hours_ebox.set_state (Gtk::STATE_ACTIVE);
845                 break;
846         case SMPTE_Minutes:
847                 minutes_ebox.set_flags (Gtk::HAS_FOCUS);
848                 minutes_ebox.set_state (Gtk::STATE_ACTIVE);
849                 break;
850         case SMPTE_Seconds:
851                 seconds_ebox.set_flags (Gtk::HAS_FOCUS);
852                 seconds_ebox.set_state (Gtk::STATE_ACTIVE);
853                 break;
854         case SMPTE_Frames:
855                 frames_ebox.set_flags (Gtk::HAS_FOCUS);
856                 frames_ebox.set_state (Gtk::STATE_ACTIVE);
857                 break;
858
859         case AudioFrames:
860                 audio_frames_ebox.set_flags (Gtk::HAS_FOCUS);
861                 audio_frames_ebox.set_state (Gtk::STATE_ACTIVE);
862                 break;
863
864         case MS_Hours:
865                 ms_hours_ebox.set_flags (Gtk::HAS_FOCUS);
866                 ms_hours_ebox.set_state (Gtk::STATE_ACTIVE);
867                 break;
868         case MS_Minutes:
869                 ms_minutes_ebox.set_flags (Gtk::HAS_FOCUS);
870                 ms_minutes_ebox.set_state (Gtk::STATE_ACTIVE);
871                 break;
872         case MS_Seconds:
873                 ms_seconds_ebox.set_flags (Gtk::HAS_FOCUS);
874                 ms_seconds_ebox.set_state (Gtk::STATE_ACTIVE);
875                 break;
876         case Bars:
877                 bars_ebox.set_flags (Gtk::HAS_FOCUS);
878                 bars_ebox.set_state (Gtk::STATE_ACTIVE);
879                 break;
880         case Beats:
881                 beats_ebox.set_flags (Gtk::HAS_FOCUS);
882                 beats_ebox.set_state (Gtk::STATE_ACTIVE);
883                 break;
884         case Ticks:
885                 ticks_ebox.set_flags (Gtk::HAS_FOCUS);
886                 ticks_ebox.set_state (Gtk::STATE_ACTIVE);
887                 break;
888         }
889
890         return FALSE;
891 }
892
893 bool
894 AudioClock::field_focus_out_event (GdkEventFocus *ev, Field field)
895 {
896         switch (field) {
897
898         case SMPTE_Hours:
899                 hours_ebox.unset_flags (Gtk::HAS_FOCUS);
900                 hours_ebox.set_state (Gtk::STATE_NORMAL);
901                 break;
902         case SMPTE_Minutes:
903                 minutes_ebox.unset_flags (Gtk::HAS_FOCUS);
904                 minutes_ebox.set_state (Gtk::STATE_NORMAL);
905                 break;
906         case SMPTE_Seconds:
907                 seconds_ebox.unset_flags (Gtk::HAS_FOCUS);
908                 seconds_ebox.set_state (Gtk::STATE_NORMAL);
909                 break;
910         case SMPTE_Frames:
911                 frames_ebox.unset_flags (Gtk::HAS_FOCUS);
912                 frames_ebox.set_state (Gtk::STATE_NORMAL);
913                 break;
914
915         case AudioFrames:
916                 audio_frames_ebox.unset_flags (Gtk::HAS_FOCUS);
917                 audio_frames_ebox.set_state (Gtk::STATE_NORMAL);
918                 break;
919
920         case MS_Hours:
921                 ms_hours_ebox.unset_flags (Gtk::HAS_FOCUS);
922                 ms_hours_ebox.set_state (Gtk::STATE_NORMAL);
923                 break;
924         case MS_Minutes:
925                 ms_minutes_ebox.unset_flags (Gtk::HAS_FOCUS);
926                 ms_minutes_ebox.set_state (Gtk::STATE_NORMAL);
927                 break;
928         case MS_Seconds:
929                 ms_seconds_ebox.unset_flags (Gtk::HAS_FOCUS);
930                 ms_seconds_ebox.set_state (Gtk::STATE_NORMAL);
931                 break;
932
933         case Bars:
934                 bars_ebox.unset_flags (Gtk::HAS_FOCUS);
935                 bars_ebox.set_state (Gtk::STATE_NORMAL);
936                 break;
937         case Beats:
938                 beats_ebox.unset_flags (Gtk::HAS_FOCUS);
939                 beats_ebox.set_state (Gtk::STATE_NORMAL);
940                 break;
941         case Ticks:
942                 ticks_ebox.unset_flags (Gtk::HAS_FOCUS);
943                 ticks_ebox.set_state (Gtk::STATE_NORMAL);
944                 break;
945         }
946
947         return FALSE;
948 }
949
950 bool
951 AudioClock::field_button_release_event (GdkEventButton *ev, Field field)
952 {
953
954
955         if (dragging) {
956                 gdk_pointer_ungrab(GDK_CURRENT_TIME);
957                 dragging = false;
958                 if (ev->y > drag_start_y+1 || ev->y < drag_start_y-1 || Keyboard::modifier_state_equals (ev->state, Keyboard::Shift)){
959                   // we actually dragged so return without setting editing focus, or we shift clicked
960
961                         return TRUE;
962                 }
963         }
964
965         if (!editable) {
966                 if (ops_menu == 0) {
967                         build_ops_menu ();
968                 }
969                 ops_menu->popup (1, ev->time);
970                 return TRUE;
971         }
972
973         if (Keyboard::is_context_menu_event (ev)) {
974                 if (ops_menu == 0) {
975                         build_ops_menu ();
976                 }
977                 ops_menu->popup (1, ev->time);
978                 return TRUE;
979         } 
980
981         switch (ev->button) {
982         case 1:
983                 switch (field) {
984                 case SMPTE_Hours:
985                         hours_ebox.grab_focus();
986                         break;
987                 case SMPTE_Minutes:
988                         minutes_ebox.grab_focus();
989                         break;
990                 case SMPTE_Seconds:
991                         seconds_ebox.grab_focus();
992                         break;
993                 case SMPTE_Frames:
994                         frames_ebox.grab_focus();
995                         break;
996
997                 case AudioFrames:
998                         audio_frames_ebox.grab_focus();
999                         break;
1000                         
1001                 case MS_Hours:
1002                         ms_hours_ebox.grab_focus();
1003                         break;
1004                 case MS_Minutes:
1005                         ms_minutes_ebox.grab_focus();
1006                         break;
1007                 case MS_Seconds:
1008                         ms_seconds_ebox.grab_focus();
1009                         break;
1010                         
1011                 case Bars:
1012                         bars_ebox.grab_focus ();
1013                         break;
1014                 case Beats:
1015                         beats_ebox.grab_focus ();
1016                         break;
1017                 case Ticks:
1018                         ticks_ebox.grab_focus ();
1019                         break;
1020                 }
1021                 break;
1022                 
1023         default:
1024                 break;
1025         }
1026
1027         return TRUE;
1028 }
1029
1030 bool
1031 AudioClock::field_button_press_event (GdkEventButton *ev, Field field)
1032 {
1033         if (session == 0) return FALSE;
1034
1035         nframes_t frames = 0;
1036
1037         switch (ev->button) {
1038         case 1:
1039                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::Shift)) {
1040                         set (frames, true);
1041                         ValueChanged (); /* EMIT_SIGNAL */
1042                                         }
1043         
1044                 /* make absolutely sure that the pointer is grabbed */
1045                 gdk_pointer_grab(ev->window,FALSE ,
1046                                  GdkEventMask( Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK |Gdk::BUTTON_RELEASE_MASK), 
1047                                  NULL,NULL,ev->time);
1048                 dragging = true;
1049                 drag_accum = 0;
1050                 drag_start_y = ev->y;
1051                 drag_y = ev->y;
1052                 break;
1053
1054         case 2:
1055                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::Shift)) {
1056                         set (frames, true);
1057                         ValueChanged (); /* EMIT_SIGNAL */
1058                 }
1059                 break;
1060
1061         case 3:
1062                 /* used for context sensitive menu */
1063                 return FALSE;
1064                 break;
1065
1066         case 4:
1067                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::Shift)) {
1068                         frames = get_frames (field);
1069                         if (frames != 0) {
1070                                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) {
1071                                         frames *= 10;
1072                                 }
1073                                 set (current_time() + frames, true);
1074                                  ValueChanged (); /* EMIT_SIGNAL */
1075                         }
1076                 }
1077                 break;
1078
1079         case 5:
1080                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::Shift)) {
1081                         frames = get_frames (field);
1082                         if (frames != 0) {
1083                                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) {
1084                                         frames *= 10;
1085                                 }
1086
1087                                 if ((double)current_time() - (double)frames < 0.0) {
1088                                         set (0, true);
1089                                 }
1090                                 else {
1091                                         set (current_time() - frames, true);
1092                                 }
1093                                 
1094                                  ValueChanged (); /* EMIT_SIGNAL */
1095                         }
1096                 }
1097                 break;
1098
1099         default:
1100                 return FALSE;
1101                 break;
1102         }
1103         
1104         return TRUE;
1105 }
1106
1107 bool
1108 AudioClock::field_button_scroll_event (GdkEventScroll *ev, Field field)
1109 {
1110         if (session == 0) return FALSE;
1111
1112         nframes_t frames = 0;
1113
1114         switch (ev->direction) {
1115
1116         case GDK_SCROLL_UP:
1117                frames = get_frames (field);
1118                if (frames != 0) {
1119                       if (Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) {
1120                              frames *= 10;
1121                       }
1122                       set (current_time() + frames, true);
1123                       ValueChanged (); /* EMIT_SIGNAL */
1124                }
1125                break;
1126
1127         case GDK_SCROLL_DOWN:
1128                frames = get_frames (field);
1129                if (frames != 0) {
1130                       if (Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) {
1131                              frames *= 10;
1132                       }
1133                       
1134                       if ((double)current_time() - (double)frames < 0.0) {
1135                              set (0, true);
1136                       } else {
1137                              set (current_time() - frames, true);
1138                       }
1139                       
1140                       ValueChanged (); /* EMIT_SIGNAL */
1141                }
1142                break;
1143
1144         default:
1145                 return FALSE;
1146                 break;
1147         }
1148         
1149         return TRUE;
1150 }
1151
1152 bool
1153 AudioClock::field_motion_notify_event (GdkEventMotion *ev, Field field)
1154 {
1155         if (session == 0 || !dragging) {
1156                 return FALSE;
1157         }
1158         
1159         float pixel_frame_scale_factor = 0.2f;
1160
1161 /*
1162         if (Keyboard::modifier_state_equals (ev->state, Keyboard::Control))  {
1163                 pixel_frame_scale_factor = 0.1f;
1164         }
1165
1166
1167         if (Keyboard::modifier_state_contains (ev->state, 
1168                                                Keyboard::Control|Keyboard::Alt)) {
1169
1170                 pixel_frame_scale_factor = 0.025f;
1171         }
1172 */
1173         double y_delta = ev->y - drag_y;
1174
1175         drag_accum +=  y_delta*pixel_frame_scale_factor;
1176
1177         drag_y = ev->y;
1178
1179         if (trunc(drag_accum) != 0) {
1180
1181                 nframes_t frames;
1182                 nframes_t pos ;
1183                 int dir;
1184                 dir = (drag_accum < 0 ? 1:-1);
1185                 pos = current_time();
1186                 frames = get_frames (field,pos,dir);
1187                 
1188                 if (frames  != 0 &&  frames * drag_accum < current_time()) {
1189                 
1190                         set ((nframes_t) floor (pos - drag_accum * frames), false); // minus because up is negative in computer-land
1191                 
1192                 } else {
1193                         set (0 , false);
1194                 
1195                 }
1196
1197                 drag_accum= 0;
1198                 ValueChanged();  /* EMIT_SIGNAL */      
1199                 
1200
1201         }
1202
1203         return TRUE;
1204 }
1205
1206 nframes_t
1207 AudioClock::get_frames (Field field,nframes_t pos,int dir)
1208 {
1209
1210         nframes_t frames = 0;
1211         BBT_Time bbt;
1212         switch (field) {
1213         case SMPTE_Hours:
1214                 frames = (nframes_t) floor (3600.0 * session->frame_rate());
1215                 break;
1216         case SMPTE_Minutes:
1217                 frames = (nframes_t) floor (60.0 * session->frame_rate());
1218                 break;
1219         case SMPTE_Seconds:
1220                 frames = session->frame_rate();
1221                 break;
1222         case SMPTE_Frames:
1223                 frames = (nframes_t) floor (session->frame_rate() / session->smpte_frames_per_second());
1224                 break;
1225
1226         case AudioFrames:
1227                 frames = 1;
1228                 break;
1229
1230         case MS_Hours:
1231                 frames = (nframes_t) floor (3600.0 * session->frame_rate());
1232                 break;
1233         case MS_Minutes:
1234                 frames = (nframes_t) floor (60.0 * session->frame_rate());
1235                 break;
1236         case MS_Seconds:
1237                 frames = session->frame_rate();
1238                 break;
1239
1240         case Bars:
1241                 bbt.bars = 1;
1242                 bbt.beats = 0;
1243                 bbt.ticks = 0;
1244                 frames = session->tempo_map().bbt_duration_at(pos,bbt,dir);
1245                 break;
1246         case Beats:
1247                 bbt.bars = 0;
1248                 bbt.beats = 1;
1249                 bbt.ticks = 0;
1250                 frames = session->tempo_map().bbt_duration_at(pos,bbt,dir);
1251                 break;
1252         case Ticks:
1253                 bbt.bars = 0;
1254                 bbt.beats = 0;
1255                 bbt.ticks = 1;
1256                 frames = session->tempo_map().bbt_duration_at(pos,bbt,dir);
1257                 break;
1258         }
1259
1260         return frames;
1261 }
1262
1263 nframes_t
1264 AudioClock::current_time (nframes_t pos) const
1265 {
1266         nframes_t ret = 0;
1267
1268         switch (_mode) {
1269         case SMPTE:
1270                 ret = smpte_frame_from_display ();
1271                 break;
1272         case BBT:
1273                 ret = bbt_frame_from_display (pos);
1274                 break;
1275
1276         case MinSec:
1277                 ret = minsec_frame_from_display ();
1278                 break;
1279
1280         case Frames:
1281                 ret = audio_frame_from_display ();
1282                 break;
1283
1284         case Off:
1285                 break;
1286         }
1287
1288         return ret;
1289 }
1290
1291 nframes_t
1292 AudioClock::current_duration (nframes_t pos) const
1293 {
1294         nframes_t ret = 0;
1295
1296         switch (_mode) {
1297         case SMPTE:
1298                 ret = smpte_frame_from_display ();
1299                 break;
1300         case BBT:
1301                 ret = bbt_frame_duration_from_display (pos);
1302                 break;
1303
1304         case MinSec:
1305                 ret = minsec_frame_from_display ();
1306                 break;
1307
1308         case Frames:
1309                 ret = audio_frame_from_display ();
1310                 break;
1311
1312         case Off:
1313                 break;
1314         }
1315
1316         return ret;
1317 }
1318
1319 void
1320 AudioClock::smpte_sanitize_display()
1321 {
1322         // Check SMPTE fields for sanity, possibly adjusting values
1323         if (atoi(minutes_label.get_text()) > 59) {
1324                 minutes_label.set_text("59");
1325         }
1326         
1327         if (atoi(seconds_label.get_text()) > 59) {
1328                 seconds_label.set_text("59");
1329         }
1330         
1331         switch ((long)rint(session->smpte_frames_per_second())) {
1332         case 24:
1333                 if (atoi(frames_label.get_text()) > 23) {
1334                         frames_label.set_text("23");
1335                 }
1336                 break;
1337         case 25:
1338                 if (atoi(frames_label.get_text()) > 24) {
1339                         frames_label.set_text("24");
1340                 }
1341                 break;
1342         case 30:
1343                 if (atoi(frames_label.get_text()) > 29) {
1344                         frames_label.set_text("29");
1345                 }
1346                 break;
1347         default:
1348                 break;
1349         }
1350         
1351         if (session->smpte_drop_frames()) {
1352                 if ((atoi(minutes_label.get_text()) % 10) && (atoi(seconds_label.get_text()) == 0) && (atoi(frames_label.get_text()) < 2)) {
1353                         frames_label.set_text("02");
1354                 }
1355         }
1356 }
1357
1358 nframes_t
1359 AudioClock::smpte_frame_from_display () const
1360 {
1361         if (session == 0) {
1362                 return 0;
1363         }
1364         
1365         SMPTE::Time smpte;
1366         nframes_t sample;
1367         
1368         smpte.hours = atoi (hours_label.get_text());
1369         smpte.minutes = atoi (minutes_label.get_text());
1370         smpte.seconds = atoi (seconds_label.get_text());
1371         smpte.frames = atoi (frames_label.get_text());
1372         smpte.rate = session->smpte_frames_per_second();
1373         smpte.drop= session->smpte_drop_frames();
1374
1375         session->smpte_to_sample( smpte, sample, false /* use_offset */, false /* use_subframes */ );
1376         
1377
1378 #if 0
1379 #define SMPTE_SAMPLE_TEST_1
1380 #define SMPTE_SAMPLE_TEST_2
1381 #define SMPTE_SAMPLE_TEST_3
1382 #define SMPTE_SAMPLE_TEST_4
1383 #define SMPTE_SAMPLE_TEST_5
1384 #define SMPTE_SAMPLE_TEST_6
1385 #define SMPTE_SAMPLE_TEST_7
1386
1387         // Testcode for smpte<->sample conversions (P.S.)
1388         SMPTE::Time smpte1;
1389         nframes_t sample1;
1390         nframes_t oldsample = 0;
1391         SMPTE::Time smpte2;
1392         nframes_t sample_increment;
1393
1394         sample_increment = (long)rint(session->frame_rate() / session->smpte_frames_per_second);
1395
1396 #ifdef SMPTE_SAMPLE_TEST_1
1397         // Test 1: use_offset = false, use_subframes = false
1398         cout << "use_offset = false, use_subframes = false" << endl;
1399         for (int i = 0; i < 108003; i++) {
1400                 session->smpte_to_sample( smpte1, sample1, false /* use_offset */, false /* use_subframes */ );
1401                 session->sample_to_smpte( sample1, smpte2, false /* use_offset */, false /* use_subframes */ );
1402
1403                 if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) {
1404                         cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1405                         cout << "smpte1: " << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> ";
1406                         cout << "sample: " << sample1 << endl;
1407                         cout << "sample: " << sample1 << " -> ";
1408                         cout << "smpte2: " << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1409                         break;
1410                 }
1411     
1412                 if (smpte2.hours != smpte1.hours || smpte2.minutes != smpte1.minutes || smpte2.seconds != smpte2.seconds || smpte2.frames != smpte1.frames) {
1413                         cout << "ERROR: smpte2 not equal smpte1" << endl;
1414                         cout << "smpte1: " << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> ";
1415                         cout << "sample: " << sample1 << endl;
1416                         cout << "sample: " << sample1 << " -> ";
1417                         cout << "smpte2: " << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1418                         break;
1419                 }
1420                 oldsample = sample1;
1421                 session->smpte_increment( smpte1 );
1422         }
1423
1424         cout << "sample_increment: " << sample_increment << endl;
1425         cout << "sample: " << sample1 << " -> ";
1426         cout << "smpte: " << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1427 #endif
1428
1429 #ifdef SMPTE_SAMPLE_TEST_2
1430         // Test 2: use_offset = true, use_subframes = false
1431         cout << "use_offset = true, use_subframes = false" << endl;
1432   
1433         smpte1.hours = 0;
1434         smpte1.minutes = 0;
1435         smpte1.seconds = 0;
1436         smpte1.frames = 0;
1437         smpte1.subframes = 0;
1438         sample1 = oldsample = 0;
1439
1440         session->sample_to_smpte( sample1, smpte1, true /* use_offset */, false /* use_subframes */ );
1441         cout << "Starting at sample: " << sample1 << " -> ";
1442         cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << endl;
1443
1444         for (int i = 0; i < 108003; i++) {
1445                 session->smpte_to_sample( smpte1, sample1, true /* use_offset */, false /* use_subframes */ );
1446                 session->sample_to_smpte( sample1, smpte2, true /* use_offset */, false /* use_subframes */ );
1447
1448 //     cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> ";
1449 //     cout << "sample: " << sample1 << endl;
1450 //     cout << "sample: " << sample1 << " -> ";
1451 //     cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1452     
1453                 if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) {
1454                         cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1455                         cout << "smpte1: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> ";
1456                         cout << "sample: " << sample1 << endl;
1457                         cout << "sample: " << sample1 << " -> ";
1458                         cout << "smpte2: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1459                         break;
1460                 }
1461     
1462                 if (smpte2.hours != smpte1.hours || smpte2.minutes != smpte1.minutes || smpte2.seconds != smpte2.seconds || smpte2.frames != smpte1.frames) {
1463                         cout << "ERROR: smpte2 not equal smpte1" << endl;
1464                         cout << "smpte1: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> ";
1465                         cout << "sample: " << sample1 << endl;
1466                         cout << "sample: " << sample1 << " -> ";
1467                         cout << "smpte2: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1468                         break;
1469                 }
1470                 oldsample = sample1;
1471                 session->smpte_increment( smpte1 );
1472         }
1473
1474         cout << "sample_increment: " << sample_increment << endl;
1475         cout << "sample: " << sample1 << " -> ";
1476         cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1477 #endif
1478
1479 #ifdef SMPTE_SAMPLE_TEST_3
1480         // Test 3: use_offset = true, use_subframes = false, decrement
1481         cout << "use_offset = true, use_subframes = false, decrement" << endl;  
1482
1483         session->sample_to_smpte( sample1, smpte1, true /* use_offset */, false /* use_subframes */ );
1484         cout << "Starting at sample: " << sample1 << " -> ";
1485         cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << endl;
1486
1487         for (int i = 0; i < 108003; i++) {
1488                 session->smpte_to_sample( smpte1, sample1, true /* use_offset */, false /* use_subframes */ );
1489                 session->sample_to_smpte( sample1, smpte2, true /* use_offset */, false /* use_subframes */ );
1490
1491 //     cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> ";
1492 //     cout << "sample: " << sample1 << endl;
1493 //     cout << "sample: " << sample1 << " -> ";
1494 //     cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1495     
1496                 if ((i > 0) && ( ((oldsample - sample1) != sample_increment) && ((oldsample - sample1) != (sample_increment + 1)) && ((oldsample - sample1) != (sample_increment - 1)))) {
1497                         cout << "ERROR: sample increment not right: " << (oldsample - sample1) << " != " << sample_increment << endl;
1498                         cout << "smpte1: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> ";
1499                         cout << "sample: " << sample1 << endl;
1500                         cout << "sample: " << sample1 << " -> ";
1501                         cout << "smpte2: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1502                         break;
1503                 }
1504     
1505                 if (smpte2.hours != smpte1.hours || smpte2.minutes != smpte1.minutes || smpte2.seconds != smpte2.seconds || smpte2.frames != smpte1.frames) {
1506                         cout << "ERROR: smpte2 not equal smpte1" << endl;
1507                         cout << "smpte1: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> ";
1508                         cout << "sample: " << sample1 << endl;
1509                         cout << "sample: " << sample1 << " -> ";
1510                         cout << "smpte2: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1511                         break;
1512                 }
1513                 oldsample = sample1;
1514                 session->smpte_decrement( smpte1 );
1515         }
1516
1517         cout << "sample_decrement: " << sample_increment << endl;
1518         cout << "sample: " << sample1 << " -> ";
1519         cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1520 #endif
1521
1522
1523 #ifdef SMPTE_SAMPLE_TEST_4
1524         // Test 4: use_offset = true, use_subframes = true
1525         cout << "use_offset = true, use_subframes = true" << endl;
1526   
1527         for (long sub = 5; sub < 80; sub += 5) {
1528                 smpte1.hours = 0;
1529                 smpte1.minutes = 0;
1530                 smpte1.seconds = 0;
1531                 smpte1.frames = 0;
1532                 smpte1.subframes = 0;
1533                 sample1 = oldsample = (sample_increment * sub) / 80;
1534     
1535                 session->sample_to_smpte( sample1, smpte1, true /* use_offset */, true /* use_subframes */ );
1536     
1537                 cout << "starting at sample: " << sample1 << " -> ";
1538                 cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << endl;
1539     
1540                 for (int i = 0; i < 108003; i++) {
1541                         session->smpte_to_sample( smpte1, sample1, true /* use_offset */, true /* use_subframes */ );
1542                         session->sample_to_smpte( sample1, smpte2, true /* use_offset */, true /* use_subframes */ );
1543       
1544                         if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1)))) {
1545                                 cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1546                                 cout << "smpte1: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> ";
1547                                 cout << "sample: " << sample1 << endl;
1548                                 cout << "sample: " << sample1 << " -> ";
1549                                 cout << "smpte2: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1550                                 //break;
1551                         }
1552       
1553                         if (smpte2.hours != smpte1.hours || smpte2.minutes != smpte1.minutes || smpte2.seconds != smpte2.seconds || smpte2.frames != smpte1.frames || smpte2.subframes != smpte1.subframes) {
1554                                 cout << "ERROR: smpte2 not equal smpte1" << endl;
1555                                 cout << "smpte1: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> ";
1556                                 cout << "sample: " << sample1 << endl;
1557                                 cout << "sample: " << sample1 << " -> ";
1558                                 cout << "smpte2: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1559                                 break;
1560                         }
1561                         oldsample = sample1;
1562                         session->smpte_increment( smpte1 );
1563                 }
1564     
1565                 cout << "sample_increment: " << sample_increment << endl;
1566                 cout << "sample: " << sample1 << " -> ";
1567                 cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1568
1569                 for (int i = 0; i < 108003; i++) {
1570                         session->smpte_to_sample( smpte1, sample1, true /* use_offset */, true /* use_subframes */ );
1571                         session->sample_to_smpte( sample1, smpte2, true /* use_offset */, true /* use_subframes */ );
1572       
1573                         if ((i > 0) && ( ((oldsample - sample1) != sample_increment) && ((oldsample - sample1) != (sample_increment + 1)) && ((oldsample - sample1) != (sample_increment - 1)))) {
1574                                 cout << "ERROR: sample increment not right: " << (oldsample - sample1) << " != " << sample_increment << endl;
1575                                 cout << "smpte1: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> ";
1576                                 cout << "sample: " << sample1 << endl;
1577                                 cout << "sample: " << sample1 << " -> ";
1578                                 cout << "smpte2: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1579                                 //break;
1580                         }
1581       
1582                         if (smpte2.hours != smpte1.hours || smpte2.minutes != smpte1.minutes || smpte2.seconds != smpte2.seconds || smpte2.frames != smpte1.frames || smpte2.subframes != smpte1.subframes) {
1583                                 cout << "ERROR: smpte2 not equal smpte1" << endl;
1584                                 cout << "smpte1: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> ";
1585                                 cout << "sample: " << sample1 << endl;
1586                                 cout << "sample: " << sample1 << " -> ";
1587                                 cout << "smpte2: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1588                                 break;
1589                         }
1590                         oldsample = sample1;
1591                         session->smpte_decrement( smpte1 );
1592                 }
1593     
1594                 cout << "sample_decrement: " << sample_increment << endl;
1595                 cout << "sample: " << sample1 << " -> ";
1596                 cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1597         }
1598 #endif
1599
1600
1601 #ifdef SMPTE_SAMPLE_TEST_5
1602         // Test 5: use_offset = true, use_subframes = false, increment seconds
1603         cout << "use_offset = true, use_subframes = false, increment seconds" << endl;
1604   
1605         smpte1.hours = 0;
1606         smpte1.minutes = 0;
1607         smpte1.seconds = 0;
1608         smpte1.frames = 0;
1609         smpte1.subframes = 0;
1610         sample1 = oldsample = 0;
1611         sample_increment = session->frame_rate();
1612
1613         session->sample_to_smpte( sample1, smpte1, true /* use_offset */, false /* use_subframes */ );
1614         cout << "Starting at sample: " << sample1 << " -> ";
1615         cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << endl;
1616
1617         for (int i = 0; i < 3600; i++) {
1618                 session->smpte_to_sample( smpte1, sample1, true /* use_offset */, false /* use_subframes */ );
1619                 session->sample_to_smpte( sample1, smpte2, true /* use_offset */, false /* use_subframes */ );
1620
1621 //     cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> ";
1622 //     cout << "sample: " << sample1 << endl;
1623 //     cout << "sample: " << sample1 << " -> ";
1624 //     cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1625     
1626 //     if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1))))
1627 //     {
1628 //       cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1629 //       break;
1630 //     }
1631     
1632                 if (smpte2.hours != smpte1.hours || smpte2.minutes != smpte1.minutes || smpte2.seconds != smpte2.seconds || smpte2.frames != smpte1.frames) {
1633                         cout << "ERROR: smpte2 not equal smpte1" << endl;
1634                         cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> ";
1635                         cout << "sample: " << sample1 << endl;
1636                         cout << "sample: " << sample1 << " -> ";
1637                         cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1638                         break;
1639                 }
1640                 oldsample = sample1;
1641                 session->smpte_increment_seconds( smpte1 );
1642         }
1643
1644         cout << "sample_increment: " << sample_increment << endl;
1645         cout << "sample: " << sample1 << " -> ";
1646         cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1647 #endif
1648
1649
1650 #ifdef SMPTE_SAMPLE_TEST_6
1651         // Test 6: use_offset = true, use_subframes = false, increment minutes
1652         cout << "use_offset = true, use_subframes = false, increment minutes" << endl;
1653   
1654         smpte1.hours = 0;
1655         smpte1.minutes = 0;
1656         smpte1.seconds = 0;
1657         smpte1.frames = 0;
1658         smpte1.subframes = 0;
1659         sample1 = oldsample = 0;
1660         sample_increment = session->frame_rate() * 60;
1661
1662         session->sample_to_smpte( sample1, smpte1, true /* use_offset */, false /* use_subframes */ );
1663         cout << "Starting at sample: " << sample1 << " -> ";
1664         cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << endl;
1665
1666         for (int i = 0; i < 60; i++) {
1667                 session->smpte_to_sample( smpte1, sample1, true /* use_offset */, false /* use_subframes */ );
1668                 session->sample_to_smpte( sample1, smpte2, true /* use_offset */, false /* use_subframes */ );
1669
1670 //     cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> ";
1671 //     cout << "sample: " << sample1 << endl;
1672 //     cout << "sample: " << sample1 << " -> ";
1673 //     cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1674     
1675 //     if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1))))
1676 //     {
1677 //       cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1678 //       break;
1679 //     }
1680     
1681                 if (smpte2.hours != smpte1.hours || smpte2.minutes != smpte1.minutes || smpte2.seconds != smpte2.seconds || smpte2.frames != smpte1.frames) {
1682                         cout << "ERROR: smpte2 not equal smpte1" << endl;
1683                         cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> ";
1684                         cout << "sample: " << sample1 << endl;
1685                         cout << "sample: " << sample1 << " -> ";
1686                         cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1687                         break;
1688                 }
1689                 oldsample = sample1;
1690                 session->smpte_increment_minutes( smpte1 );
1691         }
1692
1693         cout << "sample_increment: " << sample_increment << endl;
1694         cout << "sample: " << sample1 << " -> ";
1695         cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1696 #endif
1697
1698 #ifdef SMPTE_SAMPLE_TEST_7
1699         // Test 7: use_offset = true, use_subframes = false, increment hours
1700         cout << "use_offset = true, use_subframes = false, increment hours" << endl;
1701   
1702         smpte1.hours = 0;
1703         smpte1.minutes = 0;
1704         smpte1.seconds = 0;
1705         smpte1.frames = 0;
1706         smpte1.subframes = 0;
1707         sample1 = oldsample = 0;
1708         sample_increment = session->frame_rate() * 60 * 60;
1709
1710         session->sample_to_smpte( sample1, smpte1, true /* use_offset */, false /* use_subframes */ );
1711         cout << "Starting at sample: " << sample1 << " -> ";
1712         cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << endl;
1713
1714         for (int i = 0; i < 10; i++) {
1715                 session->smpte_to_sample( smpte1, sample1, true /* use_offset */, false /* use_subframes */ );
1716                 session->sample_to_smpte( sample1, smpte2, true /* use_offset */, false /* use_subframes */ );
1717
1718 //     cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> ";
1719 //     cout << "sample: " << sample1 << endl;
1720 //     cout << "sample: " << sample1 << " -> ";
1721 //     cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1722     
1723 //     if ((i > 0) && ( ((sample1 - oldsample) != sample_increment) && ((sample1 - oldsample) != (sample_increment + 1)) && ((sample1 - oldsample) != (sample_increment - 1))))
1724 //     {
1725 //       cout << "ERROR: sample increment not right: " << (sample1 - oldsample) << " != " << sample_increment << endl;
1726 //       break;
1727 //     }
1728     
1729                 if (smpte2.hours != smpte1.hours || smpte2.minutes != smpte1.minutes || smpte2.seconds != smpte2.seconds || smpte2.frames != smpte1.frames) {
1730                         cout << "ERROR: smpte2 not equal smpte1" << endl;
1731                         cout << "smpte: " << (smpte1.negative ? "-" : "") << smpte1.hours << ":" << smpte1.minutes << ":" << smpte1.seconds << ":" << smpte1.frames << "::" << smpte1.subframes << " -> ";
1732                         cout << "sample: " << sample1 << endl;
1733                         cout << "sample: " << sample1 << " -> ";
1734                         cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1735                         break;
1736                 }
1737                 oldsample = sample1;
1738                 session->smpte_increment_hours( smpte1 );
1739         }
1740
1741         cout << "sample_increment: " << sample_increment << endl;
1742         cout << "sample: " << sample1 << " -> ";
1743         cout << "smpte: " << (smpte2.negative ? "-" : "") << smpte2.hours << ":" << smpte2.minutes << ":" << smpte2.seconds << ":" << smpte2.frames << "::" << smpte2.subframes << endl;
1744 #endif
1745
1746 #endif  
1747
1748         return sample;
1749 }
1750
1751 nframes_t
1752 AudioClock::minsec_frame_from_display () const
1753 {
1754         if (session == 0) {
1755                 return 0;
1756         }
1757
1758         int hrs = atoi (ms_hours_label.get_text());
1759         int mins = atoi (ms_minutes_label.get_text());
1760         float secs = atof (ms_seconds_label.get_text());
1761
1762         nframes_t sr = session->frame_rate();
1763
1764         return (nframes_t) floor ((hrs * 60.0f * 60.0f * sr) + (mins * 60.0f * sr) + (secs * sr));
1765 }
1766
1767 nframes_t
1768 AudioClock::bbt_frame_from_display (nframes_t pos) const
1769 {
1770         if (session == 0) {
1771                 error << "AudioClock::current_time() called with BBT mode but without session!" << endmsg;
1772                 return 0;
1773         }
1774
1775         AnyTime any;
1776         any.type = AnyTime::BBT;
1777
1778         any.bbt.bars = atoi (bars_label.get_text());
1779         any.bbt.beats = atoi (beats_label.get_text());
1780         any.bbt.ticks = atoi (ticks_label.get_text());
1781
1782         nframes_t ret = session->convert_to_frames_at (pos, any);
1783
1784         return ret;
1785 }
1786
1787
1788 nframes_t
1789 AudioClock::bbt_frame_duration_from_display (nframes_t pos) const
1790 {
1791         if (session == 0) {
1792                 error << "AudioClock::current_time() called with BBT mode but without session!" << endmsg;
1793                 return 0;
1794         }
1795
1796         BBT_Time bbt;
1797
1798
1799         bbt.bars = atoi (bars_label.get_text());
1800         bbt.beats = atoi (beats_label.get_text());
1801         bbt.ticks = atoi (ticks_label.get_text());
1802         
1803         return session->tempo_map().bbt_duration_at(pos,bbt,1);
1804 }
1805
1806 nframes_t
1807 AudioClock::audio_frame_from_display () const
1808 {
1809         return (nframes_t) atoi (audio_frames_label.get_text());
1810 }
1811
1812 void
1813 AudioClock::build_ops_menu ()
1814 {
1815         using namespace Menu_Helpers;
1816         ops_menu = new Menu;
1817         MenuList& ops_items = ops_menu->items();
1818         ops_menu->set_name ("ArdourContextMenu");
1819
1820         Menu *mode_menu = manage (new Menu);
1821         MenuList& mode_items = mode_menu->items();
1822         mode_menu->set_name ("ArdourContextMenu");
1823         
1824         mode_items.push_back (MenuElem (_("Timecode"), bind (mem_fun(*this, &AudioClock::set_mode), SMPTE)));
1825         mode_items.push_back (MenuElem (_("Bars:Beats"), bind (mem_fun(*this, &AudioClock::set_mode), BBT)));
1826         mode_items.push_back (MenuElem (_("Minutes:Seconds"), bind (mem_fun(*this, &AudioClock::set_mode), MinSec)));
1827         mode_items.push_back (MenuElem (_("Audio Frames"), bind (mem_fun(*this, &AudioClock::set_mode), Frames)));
1828         mode_items.push_back (MenuElem (_("Off"), bind (mem_fun(*this, &AudioClock::set_mode), Off)));
1829
1830         ops_items.push_back (MenuElem (_("Mode"), *mode_menu));
1831 }
1832
1833 void
1834 AudioClock::set_mode (Mode m)
1835 {
1836         /* slightly tricky: this is called from within the ARDOUR_UI
1837            constructor by some of its clock members. at that time
1838            the instance pointer is unset, so we have to be careful.
1839            the main idea is to drop keyboard focus in case we had
1840            started editing the clock and then we switch clock mode.
1841         */
1842
1843         clock_base.grab_focus ();
1844                 
1845         if (_mode == m) {
1846                 return;
1847         }
1848         switch (_mode) {
1849         case SMPTE:
1850         case BBT:
1851         case MinSec:
1852         case Frames:
1853                 clock_base.remove ();
1854                 break;
1855         case Off:
1856                 break;
1857         }
1858         
1859         _mode = m;
1860
1861         switch (_mode) {
1862         case SMPTE:
1863                 clock_base.add (smpte_packer_hbox);
1864                 break;
1865
1866         case BBT:
1867                 clock_base.add (bbt_packer_hbox);
1868                 break;
1869
1870         case MinSec:
1871                 clock_base.add (minsec_packer_hbox);
1872                 break;
1873
1874         case Frames:
1875                 clock_base.add (frames_packer_hbox);
1876                 break;
1877
1878         case Off:
1879                 break;
1880         }
1881
1882         set_size_requests ();
1883         
1884         set (last_when, true);
1885         clock_base.show_all ();
1886         key_entry_state = 0;
1887
1888         if (!is_transient) {
1889                 ModeChanged (); /* EMIT SIGNAL */
1890         }
1891 }
1892
1893 void
1894 AudioClock::set_size_requests ()
1895 {
1896         /* note that in some fonts, "88" is narrower than "00", hence the 2 pixel padding */
1897
1898         switch (_mode) {
1899         case SMPTE:
1900                 Gtkmm2ext::set_size_request_to_display_given_text (hours_label, "-00", 5, 5);
1901                 Gtkmm2ext::set_size_request_to_display_given_text (minutes_label, "00", 5, 5);
1902                 Gtkmm2ext::set_size_request_to_display_given_text (seconds_label, "00", 5, 5);
1903                 Gtkmm2ext::set_size_request_to_display_given_text (frames_label, "00", 5, 5);
1904                 break;
1905
1906         case BBT:
1907                 Gtkmm2ext::set_size_request_to_display_given_text (bars_label, "-000", 5, 5);
1908                 Gtkmm2ext::set_size_request_to_display_given_text (beats_label, "00", 5, 5);
1909                 Gtkmm2ext::set_size_request_to_display_given_text (ticks_label, "0000", 5, 5);
1910                 break;
1911
1912         case MinSec:
1913                 Gtkmm2ext::set_size_request_to_display_given_text (ms_hours_label, "00", 5, 5);
1914                 Gtkmm2ext::set_size_request_to_display_given_text (ms_minutes_label, "00", 5, 5);
1915                 Gtkmm2ext::set_size_request_to_display_given_text (ms_seconds_label, "00.000", 5, 5);
1916                 break;
1917
1918         case Frames:
1919                 Gtkmm2ext::set_size_request_to_display_given_text (audio_frames_label, "0000000000", 5, 5);
1920                 break;
1921
1922         case Off:
1923                 break;
1924                 
1925         }
1926 }