expand display contents to include TC & BBT clocks, plus button function and track...
authorPaul Davis <paul@linuxaudiosystems.com>
Fri, 17 Jun 2016 02:51:30 +0000 (22:51 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 27 Sep 2016 19:59:29 +0000 (14:59 -0500)
So many possibilities, so little time. Really going to need a "native" widget kit before this is finished

libs/surfaces/push2/push2.cc
libs/surfaces/push2/push2.h
libs/surfaces/push2/wscript

index 263ac74dfbc62571a0df57ee0b7dad5752a7c7ce..050b541899bcf2f52a6c5c2944fce879b2f390ee 100644 (file)
 #include "pbd/failed_constructor.h"
 
 #include "midi++/parser.h"
+#include "timecode/time.h"
+#include "timecode/bbt_time.h"
 
 #include "ardour/async_midi_port.h"
 #include "ardour/audioengine.h"
 #include "ardour/debug.h"
 #include "ardour/midiport_manager.h"
 #include "ardour/session.h"
+#include "ardour/tempo.h"
+
 #include "push2.h"
 
 using namespace ARDOUR;
@@ -57,6 +61,27 @@ Push2::Push2 (ARDOUR::Session& s)
        , device_buffer (0)
        , frame_buffer (Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, cols, rows))
 {
+       context = Cairo::Context::create (frame_buffer);
+       tc_clock_layout = Pango::Layout::create (context);
+       bbt_clock_layout = Pango::Layout::create (context);
+
+       Pango::FontDescription fd ("Sans Bold 24");
+       tc_clock_layout->set_font_description (fd);
+       bbt_clock_layout->set_font_description (fd);
+
+       Pango::FontDescription fd2 ("Sans Bold 10");
+       for (int n = 0; n < 8; ++n) {
+               upper_layout[n] = Pango::Layout::create (context);
+               upper_layout[n]->set_font_description (fd2);
+               upper_layout[n]->set_text ("solo");
+               lower_layout[n] = Pango::Layout::create (context);
+               lower_layout[n]->set_font_description (fd2);
+               lower_layout[n]->set_text ("mute");
+               mid_layout[n] = Pango::Layout::create (context);
+               mid_layout[n]->set_font_description (fd2);
+               mid_layout[n]->set_text (string_compose ("Inst %1", n));
+       }
+
        if (open ()) {
                throw failed_constructor ();
        }
@@ -87,11 +112,9 @@ Push2::open ()
                return -1;
        }
 
-       device_frame_buffer[0] = new uint16_t[rows*pixels_per_row];
-       device_frame_buffer[1] = new uint16_t[rows*pixels_per_row];
+       device_frame_buffer = new uint16_t[rows*pixels_per_row];
 
-       memset (device_frame_buffer[0], 0, sizeof (uint16_t) * rows * pixels_per_row);
-       memset (device_frame_buffer[1], 0, sizeof (uint16_t) * rows * pixels_per_row);
+       memset (device_frame_buffer, 0, sizeof (uint16_t) * rows * pixels_per_row);
 
        frame_header[0] = 0xef;
        frame_header[1] = 0xcd;
@@ -137,11 +160,8 @@ Push2::close ()
                handle = 0;
        }
 
-       delete [] device_frame_buffer[0];
-       device_frame_buffer[0] = 0;
-
-       delete [] device_frame_buffer[1];
-       device_frame_buffer[1] = 0;
+       delete [] device_frame_buffer;
+       device_frame_buffer = 0;
 
        return 0;
 }
@@ -201,7 +221,7 @@ Push2::stop ()
  */
 
 int
-Push2::render ()
+Push2::bitblt_to_device_frame_buffer ()
 {
        /* ensure that all drawing has been done before we fetch pixel data */
 
@@ -212,9 +232,7 @@ Push2::render ()
 
        /* fill frame buffer (320kB) */
 
-       Glib::Threads::Mutex::Lock lm (fb_lock);
-
-       uint16_t* fb = (uint16_t*) device_frame_buffer[device_buffer];
+       uint16_t* fb = (uint16_t*) device_frame_buffer;
 
        for (int row = 0; row < rows; ++row) {
 
@@ -243,12 +261,100 @@ Push2::render ()
                fb += 64; /* 128 bytes = 64 int16_t */
        }
 
-       /* swap buffers (under lock protection) */
-       // device_buffer = (device_buffer ? 0 : 1);
-
        return 0;
 }
 
+bool
+Push2::redraw ()
+{
+       string tc_clock_text;
+       string bbt_clock_text;
+
+       if (session) {
+               framepos_t audible = session->audible_frame();
+               Timecode::Time TC;
+               bool negative = false;
+
+               if (audible < 0) {
+                       audible = -audible;
+                       negative = true;
+               }
+
+               session->timecode_time (audible, TC);
+
+               TC.negative = TC.negative || negative;
+
+               tc_clock_text = Timecode::timecode_format_time(TC);
+
+               Timecode::BBT_Time bbt = session->tempo_map().bbt_at_frame (audible);
+               char buf[16];
+
+#define BBT_BAR_CHAR "|"
+
+               if (negative) {
+                       snprintf (buf, sizeof (buf), "-%03" PRIu32 BBT_BAR_CHAR "%02" PRIu32 BBT_BAR_CHAR "%04" PRIu32,
+                                 bbt.bars, bbt.beats, bbt.ticks);
+               } else {
+                       snprintf (buf, sizeof (buf), " %03" PRIu32 BBT_BAR_CHAR "%02" PRIu32 BBT_BAR_CHAR "%04" PRIu32,
+                                 bbt.bars, bbt.beats, bbt.ticks);
+               }
+
+               bbt_clock_text = buf;
+       }
+
+       bool dirty = false;
+
+       if (tc_clock_text != tc_clock_layout->get_text()) {
+               dirty = true;
+               tc_clock_layout->set_text (tc_clock_text);
+       }
+
+       if (bbt_clock_text != tc_clock_layout->get_text()) {
+               dirty = true;
+               bbt_clock_layout->set_text (bbt_clock_text);
+       }
+
+       if (!dirty) {
+               return false;
+       }
+
+       context->set_source_rgb (0.764, 0.882, 0.882);
+       context->rectangle (0, 0, 960, 160);
+       context->fill ();
+       context->set_source_rgb (0.23, 0.0, 0.349);
+       context->move_to (650, 25);
+       tc_clock_layout->update_from_cairo_context (context);
+       tc_clock_layout->show_in_cairo_context (context);
+       context->move_to (650, 60);
+       bbt_clock_layout->update_from_cairo_context (context);
+       bbt_clock_layout->show_in_cairo_context (context);
+
+       for (int n = 0; n < 8; ++n) {
+               context->move_to (10 + (n*120), 2);
+               upper_layout[n]->update_from_cairo_context (context);
+               upper_layout[n]->show_in_cairo_context (context);
+       }
+
+       for (int n = 0; n < 8; ++n) {
+               context->move_to (10 + (n*120), 140);
+               lower_layout[n]->update_from_cairo_context (context);
+               lower_layout[n]->show_in_cairo_context (context);
+       }
+
+       for (int n = 0; n < 8; ++n) {
+               context->move_to (10 + (n*120), 120);
+               context->set_source_rgb (0.0, 0.0, 0.0);
+               mid_layout[n]->update_from_cairo_context (context);
+               mid_layout[n]->show_in_cairo_context (context);
+       }
+
+       /* render clock */
+       /* render foo */
+       /* render bar */
+
+       return true;
+}
+
 bool
 Push2::vblank ()
 {
@@ -260,12 +366,13 @@ Push2::vblank ()
                return false;
        }
 
-       {
-               Glib::Threads::Mutex::Lock lm (fb_lock);
+       if (redraw()) {
+               /* things changed */
+               bitblt_to_device_frame_buffer ();
+       }
 
-               if ((err = libusb_bulk_transfer (handle, 0x01, (uint8_t*) device_frame_buffer[device_buffer] , 2 * rows * pixels_per_row, &transferred, timeout_msecs))) {
-                       return false;
-               }
+       if ((err = libusb_bulk_transfer (handle, 0x01, (uint8_t*) device_frame_buffer , 2 * rows * pixels_per_row, &transferred, timeout_msecs))) {
+               return false;
        }
 
        return true;
@@ -302,28 +409,6 @@ Push2::set_active (bool yn)
 
                connect_session_signals ();
 
-               /* say hello */
-
-               Cairo::RefPtr<Cairo::Context> context = Cairo::Context::create (frame_buffer);
-               Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create (context);
-
-               layout->set_text ("hello, Ardour");
-               Pango::FontDescription fd ("Sans Bold 12");
-               layout->set_font_description (fd);
-
-               context->set_source_rgb (0.0, 1.0, 1.0);
-               context->rectangle (0, 0, 960, 160);
-               context->fill ();
-               context->set_source_rgb (0.0, 0.0, 0.0);
-               context->rectangle (50, 50, 860, 60);
-               context->fill ();
-               context->move_to (60, 60);
-               context->set_source_rgb ((random()%255) / 255.0, (random()%255) / 255.0, (random()%255) / 255.0);
-               layout->update_from_cairo_context (context);
-               layout->show_in_cairo_context (context);
-
-               render ();
-
                /* set up periodic task used to push a frame buffer to the
                 * device (25fps). The device can handle 60fps, but we don't
                 * need that frame rate.
index 37be3b48098f841cdf1144e6591244fdb161f28b..8f7c5e9abaf74272df351c02948301cadc15b499 100644 (file)
@@ -27,7 +27,6 @@
 #include <libusb.h>
 
 #include <cairomm/refptr.h>
-#include <glibmm/threads.h>
 
 #define ABSTRACT_UI_EXPORTS
 #include "pbd/abstract_ui.h"
 
 namespace Cairo {
        class ImageSurface;
+       class Context;
+}
+
+namespace Pango {
+       class Layout;
 }
 
 namespace MIDI {
@@ -75,9 +79,8 @@ class Push2 : public ARDOUR::ControlProtocol
 
    private:
        libusb_device_handle *handle;
-       Glib::Threads::Mutex fb_lock;
        uint8_t   frame_header[16];
-       uint16_t* device_frame_buffer[2];
+       uint16_t* device_frame_buffer;
        int  device_buffer;
        Cairo::RefPtr<Cairo::ImageSurface> frame_buffer;
        sigc::connection vblank_connection;
@@ -91,7 +94,8 @@ class Push2 : public ARDOUR::ControlProtocol
        int stop ();
        int open ();
        int close ();
-       int render ();
+       bool redraw ();
+       int bitblt_to_device_frame_buffer ();
        bool vblank ();
 
        enum ButtonID {
@@ -327,6 +331,15 @@ class Push2 : public ARDOUR::ControlProtocol
        void button_left ();
        void button_metronome ();
        void button_repeat ();
+
+       /* widgets */
+
+       Cairo::RefPtr<Cairo::Context> context;
+       Glib::RefPtr<Pango::Layout> tc_clock_layout;
+       Glib::RefPtr<Pango::Layout> bbt_clock_layout;
+       Glib::RefPtr<Pango::Layout> upper_layout[8];
+       Glib::RefPtr<Pango::Layout> mid_layout[8];
+       Glib::RefPtr<Pango::Layout> lower_layout[8];
 };
 
 
index 2acf74842dcd6e233d80b085aca6f5a59eb3fd97..d72af4e885e2fbd653343e124967d871334c594a 100644 (file)
@@ -33,7 +33,7 @@ def build(bld):
     obj.name         = 'libardour_push2'
     obj.target       = 'ardour_push2'
     obj.uselib       = 'CAIROMM PANGOMM USB'
-    obj.use          = 'libardour libardour_cp libpbd'
+    obj.use          = 'libardour libardour_cp libpbd libtimecode'
     obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
 
 def shutdown():