* added display for realtime, samplerate, buffersize
[jackpanel.git] / jackpanel / Jackpanel.vala
blob6360ea3fe4665a8700c8296537d6ef308ccead5c
1 using Gtk;
2 using Gdk;
3 using Prolooks;
5 namespace Jackpanel {
7 public class Display : DisplayBase {
8 private string _time;
9 public string time {
10 get { return _time; }
11 set {
12 if (_time != value) {
13 _time = value;
14 queue_draw ();
19 private string _time_alt;
20 public string time_alt {
21 get { return _time_alt; }
22 set {
23 if (_time_alt != value) {
24 _time_alt = value;
25 queue_draw ();
30 public bool realtime { get; set; }
32 public uint32 samplerate { get; set; }
34 public uint32 buffer_size { get; set; }
36 private uint32 _xruns;
37 public uint32 xruns {
38 get {
39 return _xruns;
41 set {
42 if (_xruns != value) {
43 _xruns = value;
44 queue_draw ();
50 Display () {
51 width = 182;
52 height = 49;
53 _time = "00:00:00";
54 set_size_request (width, height);
58 protected override bool draw_contents (Cairo.Context cr, Gdk.EventExpose event) {
59 double padding = 3;
60 double font_size = 16;
61 double smaller_font_size = font_size - 4;
62 double x = 0;
63 double y = font_size;
64 Color popup_arrow_color = color_from_string ("#ffffff");
66 ///////////////////////////// ABOVE
67 // show time text
68 text (cr, time, padding + x, y, font_size);
70 Cairo.TextExtents ext = Cairo.TextExtents();
71 cr.text_extents (time_alt, ref ext);
73 // show alt text right justified
74 text (cr, time_alt, inner_width - ext.x_advance - ext.x_bearing - padding, y, font_size);
76 ////////////////////////////// LINES
77 // draw lines
78 Color line_color;
79 Color.parse (text_color_default, out line_color);
80 set_source_from_color (cr, line_color, 0.5);
82 /* shows text boundaries for visual debugging: left bound
83 cr.move_to (x, y + ext.y_bearing);
84 cr.rel_line_to (0, ext.height);
85 cr.stroke();
88 cr.text_extents (time, ref ext);
89 // clock time separator line
90 var vline_x = padding + x + ext.x_advance + ext.x_bearing + padding + 1;
92 cr.move_to (vline_x, padding);
93 cr.rel_line_to (0, inner_height - 2 * padding + 1);
94 cr.stroke();
96 var hline_y = padding + ext.height + padding + 2;
98 // vertical separator line
99 cr.move_to (padding, hline_y);
100 cr.rel_line_to (width - 20, 0);
101 cr.stroke();
103 ////////////////////////////// BELOW
104 var y_text_below = 0.5 + hline_y + smaller_font_size;
106 // Realtime
107 string rt = "RT";
108 cr.text_extents (rt, ref ext);
109 if (realtime) {
110 text (cr, rt, padding, y_text_below, smaller_font_size);
113 var x_after_rt = padding + ext.x_advance;
115 // Xruns
116 string xruns_str = "X: %u".printf (xruns);
118 if (xruns == 0) {
119 text (cr, xruns_str, x_after_rt, y_text_below, smaller_font_size);
120 } else {
121 text (cr, xruns_str, x_after_rt, y_text_below, smaller_font_size, "#ff0000");
124 // buffer size
125 text (cr, "%u".printf (buffer_size), vline_x + padding, y_text_below, smaller_font_size);
127 // samplerate
128 string samplerate_str = "%u".printf (samplerate);
129 cr.text_extents (samplerate_str, ref ext);
130 text (cr, samplerate_str, inner_width - ext.x_advance - ext.x_bearing - padding - 1, y_text_below, smaller_font_size);
132 return false;
136 public static uint32 no_xruns;
138 static int jackpanel_xrun_callback (void *panel) {
139 no_xruns++;
140 return 0;
143 public class Jackpanel : Alignment {
144 // state
145 jack_client_t* client;
146 jack_status_t status;
147 string time_in_frames;
148 string time_in_bbt;
149 string time_h_min_sec;
151 // widgets
152 Display display;
153 TransportButton to_start;
154 TransportButton fast_backward;
155 TransportButton play;
156 TransportButton stop;
157 TransportButton fast_forward;
159 float acceleration = 1.0f;
161 private void initialize_jack (string client_name) {
162 client = jack_client_open (client_name, jack_options_t.JackNullOption, ref status);
163 if (client == null) {
164 stderr.printf ("jack_client_open() failed, status = 0x%2.0x\n", status);
165 if ((status & jack_status_t.JackServerFailed) != 0) {
166 stderr.printf ("Unable to connect to JACK server\n");
170 if ((status & jack_status_t.JackServerStarted) != 0) {
171 stderr.printf ("JACK server started\n");
173 if ((status & jack_status_t.JackNameNotUnique) != 0) {
174 client_name = jack_get_client_name(client);
175 stderr.printf ("unique name `%s' assigned\n", client_name);
177 no_xruns = 0;
178 jack_set_xrun_callback (client, jackpanel_xrun_callback, (void *)this);
180 if (jack_activate (client) != 0) {
181 stderr.printf ("cannot activate client");
185 private void show_time () {
186 jack_position_t current = jack_position_t ();
187 jack_transport_state_t transport_state;
188 uint32 frame_time;
190 transport_state = jack_transport_query (client, ref current);
191 frame_time = jack_frame_time (client);
193 var time_seconds = (int)current.frame / (int)current.frame_rate;
194 time_h_min_sec = "%02d:%02d:%02d".printf (time_seconds / 3600, (time_seconds % 3600) / 60, time_seconds % 60);
195 time_in_frames = "%u".printf ((uint32)current.frame);
197 switch (transport_state) {
198 case jack_transport_state_t.JackTransportStopped:
199 play.set_active_no_signals (false);
200 break;
201 case jack_transport_state_t.JackTransportRolling:
202 play.set_active_no_signals (true);
203 break;
204 case jack_transport_state_t.JackTransportStarting:
205 //stdout.printf ("state: Starting");
206 break;
207 default:
208 stderr.printf ("jack transport state: [unknown]");
209 break;
212 if ((current.valid & jack_position_bits_t.JackPositionBBT) != 0) {
213 time_in_bbt = "%3u|%u|%04u".printf (current.bar, current.beat, current.tick);
214 display.time_alt = time_in_bbt;
215 } else {
216 display.time_alt = time_in_frames;
219 display.time = time_h_min_sec;
222 private bool show_state () {
223 display.realtime = jack_is_realtime (client) != 0;
225 display.samplerate = jack_get_sample_rate (client);
227 display.buffer_size = jack_get_buffer_size (client);
229 display.xruns = no_xruns;
231 // this one redraws the panel
232 show_time ();
234 return true;
237 Jackpanel (string client_name) {
238 var table = new Table (5, 2, false);
239 display = new Display ();
240 to_start = new TransportButton (TransportButton.IconType.TO_START);
241 to_start.height = 20;
242 to_start.width = 31;
243 to_start.pressed += () => {
244 jack_transport_locate(client, 0);
247 fast_backward = new TransportButton (TransportButton.IconType.FAST_BACKWARD);
248 fast_backward.height = 20;
249 fast_backward.width = 31;
250 fast_backward.pressed += () => {
251 wind_transport (-1.0f);
253 Timeout.add (200, () => {
254 accelerate_transport (fast_backward, -1.0f);
258 fast_backward.released += () => {
259 acceleration = 1.0f;
262 play = new TransportButton (TransportButton.IconType.PLAY);
263 play.height = 20;
264 play.width = 31;
265 play.toggled += (button, active) => {
266 if (active) {
267 jack_transport_start (client);
268 } else {
269 jack_transport_stop (client);
273 stop = new TransportButton (TransportButton.IconType.STOP);
274 stop.height = 20;
275 stop.width = 31;
276 stop.pressed += () => {
277 jack_transport_stop (client);
278 play.active = false;
281 fast_forward = new TransportButton (TransportButton.IconType.FAST_FORWARD);
282 fast_forward.height = 20;
283 fast_forward.width = 31;
284 fast_forward.pressed += () => {
285 wind_transport (1.0f);
287 Timeout.add (200, () => {
288 accelerate_transport (fast_forward, 1.0f);
292 fast_forward.released += () => {
293 acceleration = 1.0f;
297 table.attach_defaults (display, 0, 5, 0, 1);
299 table.attach_defaults (to_start, 0, 1, 1, 2);
300 table.attach_defaults (fast_backward, 1, 2, 1, 2);
301 table.attach_defaults (fast_forward, 2, 3, 1, 2);
302 table.attach_defaults (stop, 3, 4, 1, 2);
303 table.attach_defaults (play, 4, 5, 1, 2);
305 table.set_col_spacing (0, 4);
306 table.set_col_spacing (1, 4);
307 table.set_col_spacing (2, 10);
308 table.set_col_spacing (3, 4);
310 add (table);
311 initialize_jack (client_name);
312 Timeout.add (200, show_state);
315 private void wind_transport (float direction) {
316 jack_position_t pos = jack_position_t ();
317 jack_transport_query(client, ref pos);
320 float location = (((float) pos.frame / pos.frame_rate) + direction * acceleration) * pos.frame_rate;
322 if (location < 0.0f) {
323 location = 0.0f;
326 jack_transport_locate(client, (uint32)location);
329 private bool accelerate_transport (TransportButton button, float direction) {
330 if (button.active) {
331 if (acceleration < 120.0f) {
332 acceleration *= 1.11f;
335 wind_transport (direction);
336 return true;
338 return false;
341 static int main (string[] args) {
342 Gtk.init (ref args);
343 var window = new Gtk.Window (Gtk.WindowType.TOPLEVEL);
344 var panel = new Jackpanel (Path.get_basename(args[0]));
345 window.add (panel);
346 window.destroy += Gtk.main_quit;
347 window.show_all ();
348 Gtk.main ();
349 return 0;
353 } //namespace Jackpanel