adjustments to build nascent push2 surface support
authorPaul Davis <paul@linuxaudiosystems.com>
Thu, 16 Jun 2016 02:41:01 +0000 (22:41 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 27 Sep 2016 19:59:29 +0000 (14:59 -0500)
gtk2_ardour/ardev_common.sh.in
libs/surfaces/push2/interface.cc [new file with mode: 0644]
libs/surfaces/push2/push2.cc [new file with mode: 0644]
libs/surfaces/push2/push2.h [new file with mode: 0644]
libs/surfaces/push2/render.cc [new file with mode: 0644]
libs/surfaces/push2/wscript [new file with mode: 0644]
libs/surfaces/wscript

index 6ec5d131c91cc78b2c7aacb7c4bb63660208247a..b785e36a10e3185d490261a85c407fa078507127 100644 (file)
@@ -13,7 +13,7 @@ export GTK2_RC_FILES=/nonexistent
 # can find all the components.
 #
 
-export ARDOUR_SURFACES_PATH=$libs/surfaces/osc:$libs/surfaces/faderport:$libs/surfaces/generic_midi:$libs/surfaces/tranzport:$libs/surfaces/powermate:$libs/surfaces/mackie:$libs/surfaces/wiimote
+export ARDOUR_SURFACES_PATH=$libs/surfaces/osc:$libs/surfaces/faderport:$libs/surfaces/generic_midi:$libs/surfaces/tranzport:$libs/surfaces/powermate:$libs/surfaces/mackie:$libs/surfaces/wiimote:$libs/surfaces/push2
 export ARDOUR_PANNER_PATH=$libs/panners
 export ARDOUR_DATA_PATH=$TOP:$TOP/build:$TOP/gtk2_ardour:$TOP/build/gtk2_ardour:.
 export ARDOUR_MIDIMAPS_PATH=$TOP/midi_maps:.
diff --git a/libs/surfaces/push2/interface.cc b/libs/surfaces/push2/interface.cc
new file mode 100644 (file)
index 0000000..9c89099
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+       Copyright (C) 2006,2007 Paul Davis
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation; either version 2 of the License, or
+       (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <stdexcept>
+
+#include "pbd/error.h"
+
+#include "ardour/rc_configuration.h"
+
+#include "control_protocol/control_protocol.h"
+#include "push2.h"
+
+using namespace ARDOUR;
+using namespace PBD;
+using namespace std;
+using namespace ArdourSurface;
+
+static ControlProtocol*
+new_push2 (ControlProtocolDescriptor*, Session* s)
+{
+       Push2 * p2 = 0;
+
+       try {
+               p2 = new Push2 (*s);
+               /* do not set active here - wait for set_state() */
+       }
+       catch (exception & e) {
+               error << "Error instantiating Push2 support: " << e.what() << endmsg;
+               delete p2;
+               p2 = 0;
+       }
+
+       return p2;
+}
+
+static void
+delete_push2 (ControlProtocolDescriptor*, ControlProtocol* cp)
+{
+       try
+       {
+               delete cp;
+       }
+       catch ( exception & e )
+       {
+               cout << "Exception caught trying to finalize Push2 support: " << e.what() << endl;
+       }
+}
+
+/**
+       This is called on startup to check whether the lib should be loaded.
+
+       So anything that can be changed in the UI should not be used here to
+       prevent loading of the lib.
+*/
+static bool
+probe_push2 (ControlProtocolDescriptor*)
+{
+       return Push2::probe();
+}
+
+static void*
+push2_request_buffer_factory (uint32_t num_requests)
+{
+       return Push2::request_factory (num_requests);
+}
+
+// Field names commented out by JE - 06-01-2010
+static ControlProtocolDescriptor mackie_descriptor = {
+       /*name :              */   "Ableton Push2",
+       /*id :                */   "uri://ardour.org/surfaces/push2:0",
+       /*ptr :               */   0,
+       /*module :            */   0,
+       /*mandatory :         */   0,
+       // actually, the surface does support feedback, but all this
+       // flag does is show a submenu on the UI, which is useless for the mackie
+       // because feedback is always on. In any case, who'd want to use the
+       // mcu without the motorised sliders doing their thing?
+       /*supports_feedback : */   false,
+       /*probe :             */   probe_push2,
+       /*initialize :        */   new_push2,
+       /*destroy :           */   delete_push2,
+       /*request_buffer_factory */ push2_request_buffer_factory
+};
+
+extern "C" ARDOURSURFACE_API ControlProtocolDescriptor* protocol_descriptor () { return &mackie_descriptor; }
diff --git a/libs/surfaces/push2/push2.cc b/libs/surfaces/push2/push2.cc
new file mode 100644 (file)
index 0000000..355fc62
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+       Copyright (C) 2016 Paul Davis
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation; either version 2 of the License, or
+       (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "pbd/failed_constructor.h"
+
+#include "push2.h"
+
+using namespace ARDOUR;
+using namespace std;
+using namespace PBD;
+using namespace Glib;
+using namespace ArdourSurface;
+
+#include "i18n.h"
+
+#include "pbd/abstract_ui.cc" // instantiate template
+
+Push2::Push2 (Session& s)
+       : ControlProtocol (s, string (X_("Ableton Push2")))
+       , AbstractUI<Push2Request> (name())
+       , handle (0)
+{
+       if ((handle = libusb_open_device_with_vid_pid (NULL, ABLETON, PUSH2)) == 0) {
+               throw failed_constructor ();
+       }
+
+       libusb_claim_interface (handle, 0x00);
+}
+
+Push2::~Push2 ()
+{
+       if (handle) {
+               libusb_release_interface (handle, 0x00);
+               libusb_close (handle);
+       }
+}
+
+bool
+Push2::probe ()
+{
+       libusb_device_handle *h;
+       libusb_init (NULL);
+
+       if ((h = libusb_open_device_with_vid_pid (NULL, ABLETON, PUSH2)) == 0) {
+               return false;
+       }
+
+       libusb_close (h);
+       return true;
+}
+
+void*
+Push2::request_factory (uint32_t num_requests)
+{
+       /* AbstractUI<T>::request_buffer_factory() is a template method only
+          instantiated in this source module. To provide something visible for
+          use in the interface/descriptor, we have this static method that is
+          template-free.
+       */
+       return request_buffer_factory (num_requests);
+}
+
+void
+Push2::do_request (Push2Request * req)
+{
+       // DEBUG_TRACE (DEBUG::MackieControl, string_compose ("doing request type %1\n", req->type));
+       if (req->type == CallSlot) {
+
+               call_slot (MISSING_INVALIDATOR, req->the_slot);
+
+       } else if (req->type == Quit) {
+
+               stop ();
+       }
+}
+
+int
+Push2::stop ()
+{
+       BaseUI::quit ();
+
+       return 0;
+}
diff --git a/libs/surfaces/push2/push2.h b/libs/surfaces/push2/push2.h
new file mode 100644 (file)
index 0000000..e5397e6
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+    Copyright (C) 2016 Paul Davis
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __ardour_push2_h__
+#define __ardour_push2_h__
+
+#include <vector>
+#include <map>
+#include <list>
+#include <set>
+
+#include <libusb.h>
+
+#define ABSTRACT_UI_EXPORTS
+#include "pbd/abstract_ui.h"
+#include "midi++/types.h"
+#include "ardour/types.h"
+#include "control_protocol/control_protocol.h"
+
+#define ABLETON 0x2982
+#define PUSH2   0x1967
+
+namespace ArdourSurface {
+
+struct Push2Request : public BaseUI::BaseRequestObject {
+public:
+       Push2Request () {}
+       ~Push2Request () {}
+};
+
+class Push2 : public ARDOUR::ControlProtocol
+            , public AbstractUI<Push2Request>
+{
+   public:
+       Push2 (ARDOUR::Session&);
+       ~Push2 ();
+
+       static bool probe ();
+       static void* request_factory (uint32_t);
+
+   private:
+       libusb_device_handle *handle;
+       void do_request (Push2Request*);
+       int stop ();
+};
+
+
+} /* namespace */
+
+#endif /* __ardour_push2_h__ */
diff --git a/libs/surfaces/push2/render.cc b/libs/surfaces/push2/render.cc
new file mode 100644 (file)
index 0000000..590c8e5
--- /dev/null
@@ -0,0 +1,64 @@
+#include <libusb.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include <pangomm/layout.h>
+#include <cairomm/context.h>
+#include <cairomm/surface.h>
+
+int
+deliver_image_surface (libusb_device_handle* handle, Cairo::RefPtr<Cairo::ImageSurface> surface)
+{
+       static uint8_t headerPkt[] = { 0xef, 0xcd, 0xab, 0x89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+       static uint16_t dataPkt[160*1024];
+
+       const Cairo::Format format = surface->get_format();
+
+       if (format != Cairo::FORMAT_ARGB32) {
+               return -1;
+       }
+
+       unsigned char *data = surface->get_data ();
+       const int width = surface->get_width();
+       const int height = surface->get_height();
+       const int stride = surface->get_stride();
+
+       assert (width == 960);
+       assert (height == 160);
+
+       /* fill a data packet (320kB) */
+
+       uint16_t* pkt_ptr = (uint16_t*) dataPkt;
+
+       for (int row = 0; row < height; ++row) {
+
+               uint8_t* dp = data + row * stride;
+
+               for (int col = 0; col < width; ++col) {
+
+                       /* fetch r, g, b (range 0..255). Ignore alpha */
+                       const int r = (*((uint32_t*)dp) >> 16) & 0xff;
+                       const int g = (*((uint32_t*)dp) >> 8) & 0xff;
+                       const int b = *((uint32_t*)dp) & 0xff;
+
+                       /* convert to 5 bits, 6 bits, 5 bits, respectively */
+                       /* generate 16 bit BGB565 value */
+
+                       *pkt_ptr++ = (r >> 3) | ((g & 0xfc) << 3) | ((b & 0xf8) << 8);
+
+                       dp += 4;
+               }
+
+               /* skip 128 bytes to next line. This is filler, used to avoid line borders occuring in the middle of 512
+                  byte USB buffers
+               */
+
+               pkt_ptr += 64; /* 128 bytes = 64 int16_t */
+       }
+
+       int transferred = 0;
+
+       libusb_bulk_transfer (handle, 0x01, headerPkt, sizeof(headerPkt), &transferred, 1000);
+       libusb_bulk_transfer (handle, 0x01, (uint8_t*) dataPkt, sizeof(dataPkt), &transferred, 1000);
+}
+
diff --git a/libs/surfaces/push2/wscript b/libs/surfaces/push2/wscript
new file mode 100644 (file)
index 0000000..e572ffe
--- /dev/null
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+from waflib.extras import autowaf as autowaf
+import os
+
+# Mandatory variables
+top = '.'
+out = 'build'
+
+def options(opt):
+    autowaf.set_options(opt)
+    
+def configure(conf):
+    conf.load ('compiler_cxx')
+    autowaf.configure(conf)
+    autowaf.check_pkg(conf, 'cairomm-1.0', uselib_store='CAIROMM', atleast_version='1.8.4')
+    autowaf.check_pkg(conf, 'pangomm-1.5', uselib_store='CAIROMM', atleast_version='1.4')
+
+def configure(conf):
+    autowaf.configure(conf)
+
+def build(bld):
+    obj = bld(features = 'cxx cxxshlib')
+    obj.source = '''
+            push2.cc
+           interface.cc
+    '''
+    obj.export_includes = ['.']
+    obj.defines      = [ 'PACKAGE="ardour_push2"' ]
+    obj.defines     += [ 'ARDOURSURFACE_DLL_EXPORTS' ]
+    obj.includes     = [ '.', './push2']
+    obj.name         = 'libardour_push2'
+    obj.target       = 'ardour_push2'
+    obj.uselib       = 'CAIROMM PANGOMM USB'
+    obj.use          = 'libardour libardour_cp libpbd'
+    obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
+
+def shutdown():
+    autowaf.shutdown()
index bc72446f692fdce4ae2fcf6d6a29c1c08a624299..006c907db2d418feb10ff2c321896f4b0b4f63e7 100644 (file)
@@ -39,10 +39,13 @@ def configure(conf):
     autowaf.set_recursive()
     autowaf.configure(conf)
 
-    #autowaf.check_pkg(conf, 'libusb-1.0', uselib_store='USB', mandatory=False)
+    autowaf.check_pkg(conf, 'libusb-1.0', uselib_store='USB', mandatory=False)
     #if Options.options.tranzport and conf.is_defined('HAVE_USB'):
     #    conf.define('BUILD_TRANZPORT', 1)
 
+    if conf.is_defined('HAVE_USB'):
+        children += [ 'push2' ]
+    
     if autowaf.check_pkg (conf, 'liblo', mandatory=False, uselib_store="LO", atleast_version="0.24"):
         children += [ 'osc' ]
 
@@ -77,6 +80,8 @@ def build(bld):
         bld.recurse('wiimote')
     if bld.is_defined('BUILD_TRANZPORT'):
         bld.recurse('tranzport')
+    if bld.is_defined('HAVE_USB'):
+        bld.recurse('push2')
 
 def shutdown():
     autowaf.shutdown()